呉云峰の部屋

          IntoTheWind,intoTheRain
          posts - 3, comments - 0, trackbacks - 0, articles - 5

          在c/c++語言中的頭文件其實(shí)是為了搜尋對應(yīng)的類型和函數(shù)信息的
          比如在頭文件中可以聲明一個函數(shù),但這個函數(shù)可能定義在任何地方
          比如一個靜態(tài)庫或者動態(tài)導(dǎo)入庫lib中,或者可以直接以原代碼的方式寫在cpp/c文件中
          頭文件提供的服務(wù)叫做類型映射(phototype)

          函數(shù)在c/c++語言中也是一種類型
          函數(shù)在聲明的時候其實(shí)僅僅是說明了對應(yīng)的函數(shù)調(diào)用協(xié)議,函數(shù)名稱和參數(shù)類型
          這樣就可以明確的指導(dǎo)編譯器如何創(chuàng)建這個函數(shù)對應(yīng)的調(diào)用代碼
          而尋找這個函數(shù)的工作交給了鏈接器
          注意 編譯器在vc里邊叫做cl,鏈接器在vc里邊叫做link。

          cl負(fù)責(zé)生成obj,每一個cpp/c文件會生成一個obj文件
          這個obj里邊包含了直接由c/cpp源程序所生成的匯編代碼,這個c/cpp文件需要查找的符號(這個后面再說)

          link其實(shí)和咱們上微機(jī)原理匯編課的時候用的Link很像
          他負(fù)責(zé)將每一個obj中的符號查找表中的東西轉(zhuǎn)換為一個地址
          這個地址就是最后編譯完成后的exe文件的函數(shù)對應(yīng)這個函數(shù)的入口地址。

          符號,就是這個函數(shù)或者對象通過編譯器后所產(chǎn)生的名稱
          在c語言中一個符號由這個函數(shù)或者這個對象的名稱和這個函數(shù)的調(diào)用協(xié)議組成
          這也是為什么c語言不支持重載的原因
          (還記得重載吧?重載就是參數(shù)類型或個數(shù)不同,
          參數(shù)和個數(shù)都相同的叫做重寫,重寫只能用在類的函數(shù)的繼承中)
          而c++會在每一個函數(shù)的前后添加一堆用于表示這個函數(shù)的調(diào)用方法所屬類型,名字空間和調(diào)用參數(shù)類型等的大量字符
          用來區(qū)分每一個函數(shù)
          比如一個函數(shù)
          int Test(); 根據(jù)不同的命名方法可能被不同的命名
          如果到定義了extern "C" 如下:
          extern "C" int Test();
          這個函數(shù)就被vc編譯器按c語言的方式命名為 _Test
           其中的前劃線 _表示這個函數(shù)的調(diào)用協(xié)議為__cdecl
           Test就是這個函數(shù)的名稱
          如果使用vc編譯器直接編譯這個函數(shù)int Test();
          他就被當(dāng)作int __cdecl Test(void); 編譯成  ?Test@@YAHXZ
           其中的? 和 @@YAHXZ都是編譯器加上去的
           ? 和 @@YAH 是用來表示調(diào)用協(xié)議的
           其中的H為返回值是int
           X表示沒有參數(shù)。
           Z是函數(shù)名稱結(jié)束修飾

          調(diào)用協(xié)議
          指函數(shù)的參數(shù)傳遞使用的方式
          有__cdecl __fastcall __stdcall __thiscall 等
          __cdecl 是c語言的調(diào)用方式
          __fastcall 使用寄存器傳遞參數(shù)
          __stdcall 使用棧傳遞參數(shù),并且其壓棧順序?yàn)閺挠业阶螅杀徽{(diào)用函數(shù)來清除棧
          __thiscall 是類對象的方法調(diào)用方式,這種調(diào)用方式不能直接由程序指定

          如果一個函數(shù)的是被實(shí)現(xiàn)在cpp或者c文件中的時候,就必須保證這個cpp或者c文件所產(chǎn)生的符號與這個函數(shù)的聲明所產(chǎn)生的
          符號相同,否則鏈接器在鏈接的時候就會發(fā)生無法找到符號的錯誤

          如何保證這個符號是相同的呢?
          只要在cpp或者c文件中包含這個頭文件
          或者如果能保證所生成的符號相同則根本就不用h文件也能工作
          比如如下程序

          // 這是main.cpp文件的東西
          int Test();

          int main()
          {
           Test();
          }

          // 這是test.cpp文件的東西
          int Test()
          {
           return 1;
          }
          這里就完全沒有用頭文件

          注意事項(xiàng):
          1。如果是使用了c文件作為函數(shù)的載體而編譯器為微軟的vc,
          需要在h文件中添加extern "C"通知編譯器使用c的命名規(guī)則
          最好使用判斷
          #ifdef __cplusplus
          extern "C" {
          #endif

          ...
          函數(shù)聲明
          ...

          #ifdef __cplusplus
          }
          #endif
          這樣在c編譯器上也能使用這個頭文件了
          2。c/cpp文件與頭文件名稱無關(guān)
          3。如果一個頭文件中定義了一個結(jié)構(gòu)或者類,那么在h文件中最好使用防止多次包含的
          #ifndef __XXX__H__
          #define __XXX__H__

          ...
          //類或結(jié)構(gòu)定義
          class a
          {
           ...
          };
          ...

          #endif
          這里的XXX就是這個頭文件的名稱,這個名稱是可以隨便起的,只要不起重。
          但c/cpp文件中不需要添加這些東西

          或者如果使用了vc6作為編譯器它支持
          #pragma once
          在h文件的最前面寫上這句話就可以保證這個頭文件只會被處理一遍


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 襄垣县| 通化县| 江华| 伊宁市| 云龙县| 孝感市| 通河县| 吉首市| 隆尧县| 广元市| 朔州市| 宣恩县| 肥城市| 吉木乃县| 仙游县| 定远县| 衡阳县| 奇台县| 普格县| 遂溪县| 扬州市| 巢湖市| 台东市| 青海省| 天全县| 昔阳县| 双柏县| 鹿邑县| 监利县| 福泉市| 大安市| 开封市| 门头沟区| 含山县| 申扎县| 扶风县| 疏附县| 陈巴尔虎旗| 隆子县| 聂荣县| 威远县|