當前位置:成語大全網 - 新華字典 - 壹個51單片機C程序,裏面有壹個bin的文件,這個bin文件應該包含了幾個重要的函數;能用什麽打開!

壹個51單片機C程序,裏面有壹個bin的文件,這個bin文件應該包含了幾個重要的函數;能用什麽打開!

這個壹般是打不開的,打開就等於是盜用人家的代碼。

lib文件

意義:

lib有靜態lib和動態lib之分。

使用:

lib文件通過編譯才可以使用,編譯分靜態與動態之分。

靜態:

靜態lib將導出聲明和實現都放在lib中。編譯後所有代碼都嵌入到宿主程序

動態:

動態lib相當於壹個h文件,是對實現部分(.dll文件)的導出部分的聲明。編譯後只是將導出聲明部分編譯到宿主程序中,運行時候需要相應的dll文件支持

詳細說明:

lib文件是不對外公開的,不能查看壹個編譯過後的文件

有幾個選擇:

1。如果妳查看有同名的dll文件,可以通過vc自帶的depends查看dll接口

2。通過msdn看妳使用的該lib包含的函數名,來查找其對應的頭文件,頭文件裏面有整個lib的函數聲明(可能不全)

3。查看vc或者其他工具安裝目錄下的src目錄,查看函數的代碼

lib文件是二進制文件,所以要查看它的內容,只能反匯編。

用編程語言,打開lib文件的辦法有三個:

1、在object/library modules使用全路徑名;

2、把*.lib放在VC的Lib目錄中

3、修改project setting的Link->Input中的Addtional library path,加入妳的目錄。

LIB文件是庫文件(與DLL文件相類似),供其它程序調用的,直接打不開。

內容

壹個lib文件是obj文件的集合。當然,其中還夾雜著其他壹些輔助信息,目的是為了讓編譯器能夠準確找到對應的obj文件。我們可以通過tlib.exe(在tc2.0下的根目錄)來對lib文件進行操作,妳可以把自己生成的obj文件通過tlib命令加入到壹個lib文件中,也可以把lib文件內的obj文件進行刪除操作,還可以把內部的obj文件給提取出來。明白了lib文件的大致結構以及對它的具體操作,在學習C語言的過程中,就會又多了壹個切入點對C語言具體實現進行研究。

使用步驟

在command下,把當前目錄設置為tlib.exe所在目錄,然後輸入tlib命令回車,此時顯示的內容就是對tlib命令的詳細解釋,語法如下:

Syntax: TLIB libname [/C] [/E] commands, listfile

libname library file pathname

commands sequence of operations to be performed (optional)

listfile file name for listing file (optional)

A command is of the form: <symbol>modulename, where <symbol> is:

+ add modulename to the library

- remove modulename from the library

* extract modulename without removing it

-+ or +- replace modulename in library

-* or *- extract modulename and remove it

/C case-sensitive library

/E create extended dictionary

具體解釋:

tlib libname [/C] [/E] commands, listfile

/C:大小寫敏感標誌。該選項不常用,此參數為可選項。

/E:建立擴展字典。建立擴展字典可以加速大的庫文件的連接過程,此參數同樣為可選項。

操作命令(可選項):

+ obj文件名 把指定obj文件添加到lib文件中

- obj文件名 把指定obj文件從lib文件中刪除

* obj文件名 導出指定的obj文件(導出後對應的obj文件在lib文件內仍然存在)

-+ obj文件名 替換指定的obj文件(前提是在lib文件中存在與指定obj文件同名的obj)

-* obj文件名 導出指定的obj文件(導出後把對應的obj文件從lib文件內刪除)

lib文件中obj文件列表(可選項)

此參數說明了命令運行後,生成的對應lib文件的列表文件名。它記錄了當前lib文件內obj文件列表

與dll區別編輯

(1)lib是編譯時需要的,dll是運行時需要的。

如果要完成源代碼的編譯,有lib就夠了。

如果也使動態連接的程序運行起來,有dll就夠了。

在開發和調試階段,當然最好都有。

(2)壹般的動態庫程序有lib文件和dll文件。lib文件是必須在編譯期就連接到應用程序中的,而dll文件是運行期才會被調用的。如果有dll文件,那麽對應的lib文件壹般是壹些索引信息,具體的實現在dll文件中。如果只有lib文件,那麽這個lib文件是靜態編譯出來的,索引和實現都在其中。靜態編譯的lib文件有好處:給用戶安裝時就不需要再掛動態庫了。但也有缺點,就是導致應用程序比較大,而且失去了動態庫的靈活性,在版本升級時,同時要發布新的應用程序才行。

(3)在動態庫的情況下,有兩個文件,壹個是引入庫(.LIB)文件,壹個是DLL文件,引入庫文件包含被DLL導出的函數的名稱和位置,DLL包含實際的函數和數據,應用程序使用LIB文件鏈接到所需要使用的DLL文件,庫中的函數和數據並不復制到可執行文件中,因此在應用程序的可執行文件中,存放的不是被調用的函數代碼,而是DLL中所要調用的函數的內存地址,這樣當壹個或多個應用程序運行時再把程序代碼和被調用的函數代碼鏈接起來,從而節省了內存資源。從上面的說明可以看出,DLL文件必須隨應用程序壹起發行,否則應用程序將會產生錯誤。

加載方法編輯

直接加入

在VC中打開File View壹頁,選中工程名,單擊鼠標右鍵,然後選中"Add Files to Project"菜單,在彈出的文件對話框中選中要加入DLL的LIB文件即可。

設置

打開工程的 Project Settings菜單,選中Link,然後在Object/library modules下的文本框中輸入DLL的LIB文件。

程序代碼

加入預編譯指令#pragma comment (lib,"*.lib"),這種方法優點是可以利用條件預編譯指令鏈接不同版本的LIB文件。因為,在Debug方式下,產生的LIB文件是Debug版本,如Regd.lib;在Release方式下,產生的LIB文件是Release版本,如Regr.lib。

當應用程序對DLL的LIB文件加載後,還需要把DLL對應的頭文件(*.h)包含到其中,在這個頭文件中給出了DLL中定義的函數原型,然後聲明。

詳解

節的概念編輯

Lib格式只有四種類型的節(Section),即First Sec,Second Sec,Longname Sec和Obj Sec;其中Second Sec與Longname Sec是可選節,很多Lib文件中都沒有。而開頭的Singature只是壹個標識,它相當於COFF目標文件中的魔法數字。它是壹個長度為8的字符串,值為“!<arch>\n”。

First Sec 顧名思義,就是第壹個節。它包含了庫中所有的符號名以及這些符號所在的目標文件在庫中的位置(絕對偏移)。

Second Sec 就是第二節。它的內容和First Sec是相同的。不同的是,Second Sec是壹個有序表,通過它來查找庫中的符號比通過First Sec來查找要快很多。

Longname Sec 是長名稱節。這壹節是壹個字符串表。它包含了所有長目標文件名。如果後面的Obj Sec中沒有給出相應的目標文件名,我們就要到這壹節中來查找。

Obj Sec 就是目標文件節。這些節中存儲著不同的目標文件的原始數據。

在庫文件中,每壹節都有兩個部分。壹個部分是頭,另壹個部分才是該節的數據;數據緊跟在頭的後面。頭描述了該節數據的類型、長度等信息。這些頭的格式都是相同的。其結構用C語言描述如下:

typedef struct {

char Name[16]; // 名稱

char Time[12]; // 時間

char UserID[6]; // 用戶ID

char GroupID[6]; // 組ID

char Mode[8]; // 模式

char Size[10]; // 長度

char EndOfHeader[2];// 結束符

} SectionHeader;

可以看到,頭中的數據全都是字符串。用字符串的好處是可以提高格式的兼容性,因為在不同的機器上,數據的排列方式是不同的。有的機器是以Little-Endian方式工作,還有的是以Big-Endian方式工作,它們互不兼容(這兩種方式的區別!?請看我的《COFF格式》壹文,其中的文件頭壹節有說明)。用字符串就不會有這種問題(後面我們將會遇到)。但它也有不方便的地方,就是必須把字符串轉換成數值,多了壹個步驟。

在這個結構中,最常用的Name、Size以及EndOfHeader三個成員。Name就是節的名稱啦!Size也很好理解,就是該節數據的長度。其內容為“`\n”(註意,這裏沒有打錯,是兩個字符“`”和“\n”)。怎麽樣?有點奇怪吧?為什麽要有這個結束符?每壹節的頭長度壹定,每節中的數據長度也知道。按順序向下讀不行嗎?答案是:不行!因為每壹節之間存在間隙!通常是壹個字節或零個字節。如果是零個字節倒好,按順序向下讀是OK的。可是如果不為零的話,這樣讀就要錯位了。要知道錯位沒有,只好用壹個結束符來定位了。如果在讀頭的時候發現結束符不對,那就要壹個字節壹個字節地向下查找,直到找到結束符,才能算是對齊了。切記!切記!

當然,通過First Sec或Second Sec中給出的偏移來讀數據就不存在這個問題。不會發生錯位,放心讀吧!

First Sec

第壹節,通常就是Lib中的每壹個小節。它的名稱是“/”。其數據部分的結構如下:

typedef struct {

unsigned long SymbolNum; // 庫中符號的數量

unsigned long SymbolOffset[n]; // 符號所在目標節的偏移

char StrTable[m]; // 符號名稱字符串表

}FirstSec;

第壹個成員SymbolNum是符號的數量。註意!它是以Big-Endian方式儲存的(x86平臺上的數據是以Little-Endian方式儲存的。這裏應該註意轉換。後面給出的convert函數可以在Little-Endian格式與Big-Endian格式之間進行相互轉換)。

第二個成員SymbolOffset是壹個數組,它的長度n就是符號的數量,也就是SymbolNum。這個數組儲存了每壹個符號所在的目標節的偏移。我們可以方便地通過它來查找符號所在的目標文件。註意!它也是以Big-Endian格式儲存的。

第三個成員StrTable是壹個字符串表,它的長度m就是SectionHeader.Size的值減去(SymbolNum+1)*4。其結構很簡單,就是壹堆以‘\0’結尾的字符串(和COFF文件中的字符串表結構相同)。在有的系統中,它還可能是以“/\n”這兩個字符結尾的字符串的集合。

很簡單的壹個結構,不過有兩個成員的長度是不定的。怎麽才能方便地從Lib中讀出這些數據,留給大家自己想吧!下面我只給出壹個進行Little-Endian與Big-Endian互轉的函數。

inline void convert(void * p // 要轉換的數據的指針

,size_tsize = 4 // 數據的長度,long為4,short為2

) {

char * buf=(char*)p;

char temp;

for ( size_t i=0;i<size/2;i++ ) {

temp=buf[i];

buf[i]=buf[size-i-1];

buf[size-i-1]=temp;

}

}

Second Sec

第二節

這壹節與第壹節很相似!它通常也就是Lib文件的第二個節。它的名字也是“/”(註意:文件中第壹個叫“/”的節是第壹節,第二個就是第二節)。不過它的結構與第壹節有些不同,如下:

typedef struct {

unsigned long ObjNum; // Obj Sec的數量

unsigned long ObjOffset[x]; // 每壹個Obj Sec的偏移

unsigned long SymbolNum; // 庫中符號的數量

unsigned short SymbolIdx[n]; // 符號在ObjOffset表中的索引

char StrTable[m]; // 符號名稱字符串表

}SecondSec;

第壹個成員ObjNum是庫中Obj Sec的數量。

第二個成員ObjOffset是壹個偏移表,它記錄了庫中所有Obj Sec的偏移。這個表的記錄數x就是ObjNum。

第三個成員SymbolNum與First Sec中的SymbolNum意義相同。

第四個成員SymbolIdx變成了壹個索引,它記錄了相應名稱字符串在ObjOffset這個表中的位置,我們要通過兩次索引才能找到我們所要符號的Obj Sec位置。它的項目數n為SymbolNum。但請註意,這個索引是unsigned short型,不再是unsigned long型。

第五個成員StrTable結構與First Sec中的壹樣。不過,它的長度m為SectionHeader.Size的值減去((ObjNum+1)*4+(SymbolNum+2)*2)。

值得註意的是,這裏的所有數據都是Little-Endian格式的。千萬不要弄錯了!Longname Sec

這個小節就是壹個字符串表,它的名稱為“//”,其結構同FirstSec.StrTable。這裏就不多說了。

Obj Sec

這壹節中的數據就是COFF文件的原始數據,把它讀出來存成文件,就是壹個COFF文件。它的格式請參考《COFF格式》壹文。

要指出的是它的命名方式有些特殊。如果Obj文件的名稱少於16個字符,它就會被保存在SectionHeader的Name成員中,以‘/’字符結尾。如果無法保存在Name成員中,則Name成員的第壹個字符就為‘/’,之後再跟上這個名稱在Longname Sec中的偏移。

例如:

!<arch>\n

……

LongName Sec:

This_Is_Long_Name0001\0

This_Is_Long_Name0002\0

……

Obj Sec1:

Name[16]:“shortname/”

……

Obj Sec2:

Name[16]:“/0” // 這裏使用了第壹個長文件名This_Is_Long_Name0001

……

Obj Sec3:

Name[16]:“/22” // 這裏使用了第二個長文件名This_Is_Long_Name0002