1. 程式人生 > 其它 >預處理、動態庫、靜態庫

預處理、動態庫、靜態庫

預處理

c語言編譯過程

Linux下GCC編譯器編譯過程

  • 1 預編譯

    .c的標頭檔案展開、巨集定義
    生成的檔案是.i檔案

  • 2 編譯

    將預處理之後的.i檔案生成.s彙編檔案

  • 3 彙編

    將.s彙編檔案生成.o目標檔案

  • 4 連結

    將.o檔案連結成目標檔案

gcc -E hello.c -o hello.i  	1.預處理
gcc -S hello.i -o hello.s 	2.編譯
gcc -c hello.s -o hello.o	3.彙編
gcc hello.o -0 hello_elf 	4.連結

include

  • #include <> //用尖括號包含標頭檔案,在系統指定的路徑下找標頭檔案

  • #include "" //用雙引號包含標頭檔案,先在當前目錄下找標頭檔案,找不到,再到系統指定的路徑下找。

  • 注意: include 經常用來包含標頭檔案,可以包含 .c 檔案,但是不要包含 .c ,因為include包含的檔案會在預編譯被展開,如果一個.c被包含多次,展開多次,會導致函式重複定義。所以不要包含.c檔案。

  • 注意:預處理只是對include等預處理操作進行處理並不會進行語法檢查,這個階段有語法錯誤也不會報錯,第二個階段即編譯階段才進行語法檢查。

define

  • 巨集定義用define定義

  • 巨集是在預編譯的時候進行替換

不帶參巨集

作用範圍: 從定義的地方到本檔案末尾,如果想在中間終止巨集的定義範圍#undef 變數名

//測試巨集定義
#define PI 3.14
int main(){
	
	printf("PI = %f",PI); //PI = 3.140000
	
	#undef PI //撤銷巨集定義 
	
	//printf("PI = %f",PI); // 編譯都通不過,因為巨集定義已經撤銷了 
	
	#define PI 3.1415926 //重新巨集定義 
	printf("PI = %f",PI); //PI = 3.141593
	return 0;
}; 

帶參巨集
#define S(a,b) a*b

  • 注意帶參巨集的形參a和b沒有型別名

  • S(2,4)將來在預處理的時候替換成 實參替代字串的形參,其他字元保留

 //代參巨集定義 
#define S(a,b) a*b
#define B(a,b) (a)*(b) //保證優先順序,消歧義
 
int main(){
	
	int a = S(2,3);
	printf("a = %d\n",a); // a = 6 
	a= S(3+2,3);
	printf("a = %d\n",a); // a = 9 ,相當於 3+2*3 沒有括號可能有歧義 
	a= B(3+2,3);
	printf("a = %d\n",a); //a = 15
	return 0;
}

帶參巨集與帶參函式區別

  • 帶參巨集被呼叫多少次就會被展開多少次,執行程式碼的時候沒有函式呼叫的過程,不需要壓棧彈棧。所以帶參巨集,是浪費了空間,因為被展開多次,節省時間
  • 帶參函式,程式碼只有一行,存在程式碼段,呼叫的時候去程式碼段取程式碼,呼叫的時候要。壓棧彈棧。有個呼叫的過程。
  • 所以說,帶參函式浪費了時間,節省了空間
  • 帶參函式的形參是有型別的,帶參巨集的形參沒有型別名

選擇性編譯

ifdef

//選擇性編譯
	#ifdef S  // S代表一個巨集 
		//如果巨集存在,就會編譯 
		printf("巨集存在,編譯"); 
	#else
		//不存在,就不會編譯
		printf("巨集不存在,不編譯"); 	
	#endif 
	 

ifndef

	 #ifndef S
	 	//如果巨集存在,就會編譯 
	 	printf("巨集存在,不編譯"); 
	 #else
	 	//不存在,就不會編譯
	 	printf("巨集不存在,編譯"); 	
	 #endif 
	

這種方法常用語放置標頭檔案重複包含

#ifndef _5h //沒有定義才會編譯 

#define _5h	//下面定義了,所以下次引入就不會在編譯了 
extern int a;

#endif

if

	#if 1
	 	//如果表示式為真,就會編譯 
	 	printf("表示式為真,編譯"); 
	#else
	 	//如果表示式為假,就不會編譯
	 	printf("表示式為假,不編譯"); 	
	#endif

靜態庫

1.動態編譯

  • 動態編譯使用的是動態庫檔案進行編譯
    gcc hello.c -o hello
  • 預設使用動態編譯方法

2.靜態編譯

  • 靜態編譯使用的靜態庫檔案進行編譯
    gcc -static hello.c -o hello

3.靜態編譯和動態編譯區別

  • 1 使用庫檔案格式不一樣,動態編譯使用動態庫,靜態編譯使用靜態庫
  • 2 態編譯要把靜態庫檔案打包編譯到可執行程式中
  • 3 動態編譯不會把動態庫檔案打包編譯到可執行程式中,他只是編譯連結關係