做外貿(mào)不能訪問(wèn)國(guó)外網(wǎng)站怎么辦教程推廣優(yōu)化網(wǎng)站排名
頭文件的作用
通常,一個(gè)常規(guī)的C語(yǔ)言程序會(huì)包含多個(gè)源碼文件(.c),當(dāng)某些公共資源需要在各個(gè)源碼文件中使用時(shí),為了避免多次編寫(xiě)相同的代碼,一般的做法是將這些大家都需要用到的公共資源放入頭文件(.h)當(dāng)中,然后在各個(gè)源碼文件中直接包含即可。
頭文件的內(nèi)容
- 頭文件中所存放的內(nèi)容,就是各個(gè)源碼文件的彼此可見(jiàn)的公共資源,包括:
- 全局變量的聲明。
- 普通函數(shù)的聲明。
- 靜態(tài)函數(shù)的定義。
- 宏定義。
- 結(jié)構(gòu)體、聯(lián)合體的聲明。
- 枚舉常量列表的聲明。
- 其他頭文件。
示例代碼:
// head.h
extern int global; // 1,全局變量的聲明
extern void f1(); // 2,普通函數(shù)的聲明
static void f2() // 3,靜態(tài)函數(shù)的定義
{...
}
#define MAX(a, b) ((a)>(b)?(a):(b)) // 4,宏定義
struct node // 5,結(jié)構(gòu)體的定義
{...
};
union attr // 6,聯(lián)合體的定義
{...
};
#include <unistd.h> // 7,其他頭文件
#include <string.h>
#include <stdint.h>
- 特別說(shuō)明:
-
- 全局變量、普通函數(shù)的定義一般出現(xiàn)在某個(gè)源文件(*.c *.cpp)中,其他的源文件想要使用都需要進(jìn)行聲明,因此聲明語(yǔ)句一般放在頭文件中更方便。
- 靜態(tài)函數(shù)、宏定義、結(jié)構(gòu)體、聯(lián)合體的聲明都只能在其所在的文件可見(jiàn),因此如果多個(gè)源文件都需要使用的話,放到頭文件中定義是最方便,也是最安全的選擇。
頭文件的使用
頭文件編寫(xiě)好了之后,就可以被各個(gè)所需要的源碼文件包含了,包含頭文件的語(yǔ)句就是如下預(yù)處理指令:
// main.c
#include "head.h" // 包含自定義的頭文件
#include <stdio.h> // 包含系統(tǒng)預(yù)定義的文件int main()
{...
}
頭文件包含的細(xì)節(jié):
#include <stdio.h>
/*
#include <...> search starts here: <>默認(rèn)從以下系統(tǒng)路徑尋找/usr/lib/gcc/x86_64-linux-gnu/11/include/usr/local/include/usr/include/x86_64-linux-gnu/usr/include
End of search list.*/#include "./inc/myHead.h" // 使用雙引號(hào)包含的頭文件會(huì)從當(dāng)前代碼所處的路徑下搜索
// 由于一般我們自己寫(xiě)的頭文件會(huì)于項(xiàng)目存放在同一個(gè)路徑下
// 因此一般會(huì)使用雙引號(hào)來(lái)包含自己(非系統(tǒng)的頭文件)編寫(xiě)的頭文件
// 以上例子中有寫(xiě)該頭文件的詳細(xì)路徑,因此編譯時(shí)直接gcc 即可#include "myHead.h" // 沒(méi)有寫(xiě)明頭文件的具體相對(duì)路徑
// 因此編譯時(shí)需要告知編譯器被你存儲(chǔ)與哪個(gè)文件
gcc xxx.c -I./inc
-I 用于告知編譯器頭文件的路徑
./inc 則是具體的路徑值
可以看到,在源碼文件中包含指定的頭文件有兩種不同的形式:
- 使用雙引號(hào):在指定位置 + 系統(tǒng)標(biāo)準(zhǔn)路徑搜索 head.h
- 使用尖括號(hào):在系統(tǒng)標(biāo)準(zhǔn)路徑搜索 stdio.h
由于自定義的頭文件一般放在源碼文件的周圍,因此需要在編譯的時(shí)候通過(guò)特定的選項(xiàng)來(lái)指定位置,而系統(tǒng)頭文件都統(tǒng)一放在標(biāo)準(zhǔn)路徑下,一般無(wú)需指定位置。
假設(shè)在源碼文件 main.c 中,包含了兩個(gè)頭文件:head.h 和 stdio.h ,由于他們一個(gè)是自定義頭文件,一個(gè)是系統(tǒng)標(biāo)準(zhǔn)頭文件,前者放在項(xiàng)目 pro/inc 路徑下,后者存放于系統(tǒng)頭文件標(biāo)準(zhǔn)路徑下(一般位于 /usr/include),因此對(duì)于這個(gè)程序的編譯指令應(yīng)寫(xiě)作:
gec@ubuntu:~/pro$ gcc main.c -o main -I./inc
頭文件的格式
由于頭文件包含指令 #include 的本質(zhì)是復(fù)制粘貼,并且一個(gè)頭文件中可以嵌套包含其他頭文件,因此很容易出現(xiàn)一種情況是:頭文件被重復(fù)包含。
- 使用條件編譯,解決頭文件重復(fù)包含的問(wèn)題,格式如下:
- 作用:防止頭文件被多次重復(fù)包含后出現(xiàn)重復(fù)定義的問(wèn)題
#ifndef _HEADNAME_H
#define _HEADNAME_H...
... (頭文件正文)
...#endif
其中,HEADNAME一般取頭文件名稱的大寫(xiě)
項(xiàng)目的基本框架:
編譯命令:
gcc src/*.c -o bin/demo -I./incgcc #編譯命令
src/*.c #需要編譯的源文件 *.c 表示該路徑下的所有.c文件
-o #指明輸出的文件名字
bin/demo #具體輸出的可執(zhí)行文件路徑+名字
-I./inc # -I指定頭文件的路徑 ./inc 具體的路徑
C語(yǔ)言的關(guān)鍵字:
在C語(yǔ)言中,以下是一些關(guān)鍵字及其作用:1. #include:預(yù)處理指令,用于包含頭文件。例如:#include <stdio.h> 包含頭文件 stdio.h,以便使用其中的函數(shù)。2. #define:預(yù)處理指令,用于定義宏。例如:#define MAX 1000 定義一個(gè)宏 MAX,值為 1000。3. #undef:預(yù)處理指令,用于取消定義宏。例如:#undef MAX 取消定義宏 MAX。4. #ifdef:預(yù)處理指令,用于檢查當(dāng)前定義的宏是否已定義。例如:#ifdef MACRO 檢查是否定義了宏 MACRO。5. #ifndef:預(yù)處理指令,用于檢查當(dāng)前定義的宏是否未定義。例如:#ifndef MACRO 檢查是否未定義宏 MACRO。6. #else:預(yù)處理指令,用于實(shí)現(xiàn)條件編譯。例如:#ifdef MACRO #else 表示當(dāng)宏 MACRO 已定義時(shí)執(zhí)行 #else 中的代碼。7. #elif:預(yù)處理指令,用于實(shí)現(xiàn)條件編譯的 elif 分支。例如:#ifdef MACRO #elif MACRO2 表示當(dāng)宏 MACRO 已定義時(shí)執(zhí)行 #elif MACRO2 中的代碼。8. #endif:預(yù)處理指令,用于結(jié)束條件編譯。例如:#endif 結(jié)束條件編譯。9. #error:預(yù)處理指令,用于生成錯(cuò)誤信息。例如:#error "Error message" 生成錯(cuò)誤信息 "Error message"。10. #pragma:預(yù)處理指令,用于提供編譯器特定的信息。例如:#pragma pack(1) 告訴編譯器使用大小為 1 的對(duì)齊方式。11. #volatile:預(yù)處理指令,用于指示對(duì)變量的訪問(wèn)應(yīng)該使用寄存器方式。例如:#volatile 修飾的變量在匯編語(yǔ)言中不會(huì)被優(yōu)化。12. #restrict:預(yù)處理指令,用于提示編譯器使用 restrict 屬性。例如:#restrict int *a 修飾的指針 a,編譯器會(huì)使用 restrict 屬性。13. auto:關(guān)鍵字,用于指定變量為自動(dòng)變量。例如:auto int a 聲明一個(gè)自動(dòng)變量 a。14. static:關(guān)鍵字,用于指定變量為靜態(tài)變量。例如:static int a 聲明一個(gè)靜態(tài)變量 a。15. register:關(guān)鍵字,用于指定變量為寄存器變量。例如:register int a 聲明一個(gè)寄存器變量 a。16. volatile:關(guān)鍵字,用于指定變量為 volatile 變量。例如:volatile int a 聲明一個(gè) volatile 變量 a。17. const:關(guān)鍵字,用于指定變量為常量。例如:const int a 聲明一個(gè)常量變量 a。18. inline:關(guān)鍵字,用于指定函數(shù)為內(nèi)聯(lián)函數(shù)。例如:inline void func() { ... } 聲明一個(gè)內(nèi)聯(lián)函數(shù) func。19. extern:關(guān)鍵字,用于指定變量為外部變量。例如:extern int a 聲明一個(gè)外部變量 a。20. __cdecl、__stdcall、__fastcall、__thiscall:調(diào)用約定,用于指定函數(shù)的調(diào)用方式。例如:__cdecl void func() { ... } 聲明一個(gè)使用 __cdecl 調(diào)用約定函數(shù) func。21. __attribute__:屬性,用于指定函數(shù)的屬性,如限制參數(shù)數(shù)量、設(shè)置棧大小等。例如:__attribute__((stdcall)) void func(int arg) { ... } 聲明一個(gè)使用 stdcall 調(diào)用約定函數(shù) func,并限制參數(shù)數(shù)量為 int arg。22. __packed:屬性,用于指定變量或結(jié)構(gòu)體的對(duì)齊方式。例如:__packed int a 聲明一個(gè)使用 __packed 屬性變量 a。23. __section:屬性,用于指定變量或結(jié)構(gòu)體放置的節(jié)區(qū)。例如:__section(".data") int a 聲明一個(gè)使用 __section(".data") 屬性變量 a。24. __alignof__:運(yùn)算符,用于獲取變量或類型的對(duì)齊字節(jié)數(shù)。例如:__alignof__(int) 獲取 int 類型的對(duì)齊字節(jié)數(shù)。25. __builtin_offsetof:函數(shù),用于獲取結(jié)構(gòu)體中成員的偏移量。例如:__builtin_offsetof(struct my_struct, my_member) 獲取 struct my_struct 中的 my_member 成員的偏移量。26. __has_feature:宏,用于檢查編譯器是否具有某些特性。例如:__has_feature(c++11) 檢查編譯器是否具有 c++11 特性。27. __is_available:宏,用于檢查某個(gè)特性是否可用。例如:__is_available("avx") 檢查 avx 特性是否可用。28. __clang_builtin_macro:宏,用于檢查某個(gè)宏是否為 clang 內(nèi)置宏。例如:__clang_builtin_macro("__clang_max__") 檢查 __clang_max__ 是否為 clang 內(nèi)置宏。29. __GNUC_MINOR__:宏,用于獲取 gcc 版本的小版本號(hào)。例如:__GNUC_MINOR__ 獲取 gcc 的 minor 版本號(hào)。30. __GNUC_PATCHLEVEL__:宏,用于獲取 gcc 版本的補(bǔ)丁版本號(hào)。例如:__GNUC_PATCHLEVEL__ 獲取 gcc 的 patchlevel 版本號(hào)。
結(jié)語(yǔ):
????????在這篇博客中,我們?cè)敿?xì)探討了C語(yǔ)言中頭文件的概念及其重要性。頭文件作為代碼組織的一部分,不僅便利了函數(shù)和變量的聲明,也使得不同源文件之間的協(xié)作變得更加高效。通過(guò)合理地使用頭文件,我們能夠模塊化代碼,提高可讀性和可維護(hù)性。
????????此外,了解如何創(chuàng)建和管理自定義頭文件,能夠幫助我們減少代碼重復(fù),提升項(xiàng)目的結(jié)構(gòu)性。在實(shí)際開(kāi)發(fā)中,正確使用頭文件可以降低錯(cuò)誤的發(fā)生率,并使調(diào)試過(guò)程更加順暢。
????????希望這篇文章能夠幫助您深入理解C語(yǔ)言中的頭文件,以及如何在項(xiàng)目中有效地使用它們。隨著編程技能的提升,對(duì)代碼結(jié)構(gòu)和組織方式的重視將為您的開(kāi)發(fā)工作帶來(lái)長(zhǎng)遠(yuǎn)的好處。感謝您的閱讀,期待與您在今后的討論中共同分享和學(xué)習(xí)更多編程知識(shí)!