1. 程式人生 > 其它 >編譯選項學習總結(原創,禁止轉載)

編譯選項學習總結(原創,禁止轉載)

基本選項

一般來講,C/C++從原始碼到可執行程式之間要經歷四個步驟:

預處理:展開標頭檔案/巨集替換/去掉註釋/條件編譯

編譯:檢查語法,生成彙編

彙編:彙編程式碼轉換機器碼

連結:連結到一起生成可執行程式

-E:只進行預處理,不編譯

執行指令

gcc -E test.c

命令列顯示出預處理資訊,但不生成檔案

gcc -E hello.c > 1.txt

將相關預處理資訊重定向到檔案1.txt中,檔案內容顯示如下

typedef signed char __int8_t;
typedef unsigned char __uint8_t;
typedef short __int16_t;
typedef unsigned short __uint16_t;
typedef int __int32_t;
typedef unsigned int __uint32_t;
typedef long long __int64_t;
typedef unsigned long long __uint64_t;
typedef long __darwin_intptr_t;
typedef unsigned int __darwin_natural_t;
typedef int __darwin_ct_rune_t;
typedef union {
 char __mbstate8[128];
 long long _mbstateL;
} __mbstate_t;
typedef __mbstate_t __darwin_mbstate_t;
									.
                  .
                  .

-S:只編譯,不彙編

執行指令

gcc -S test.c

生成檔案test.s,檔案內容如下:

	.section	__TEXT,__text,regular,pure_instructions
	.build_version macos, 11, 0	sdk_version 11, 3
	.globl	_main                           ## -- Begin function main
	.p2align	4, 0x90
_main:                                  ## @main
	.cfi_startproc
## %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	subq	$16, %rsp
	movl	$0, -4(%rbp)
	leaq	L_.str(%rip), %rdi
	movb	$0, %al
	callq	_printf
	xorl	%ecx, %ecx
	movl	%eax, -8(%rbp)                  ## 4-byte Spill
	movl	%ecx, %eax
	addq	$16, %rsp
	popq	%rbp
	retq
	.cfi_endproc
                                        ## -- End function
	.section	__TEXT,__cstring,cstring_literals
L_.str:                                 ## @.str
	.asciz	"hello\n"
.subsections_via_symbols

表明此時根據原始檔生成了彙編程式碼

-c:只編譯、彙編,不連結

執行指令

gcc -c test.c

此時原始檔經過編譯和彙編直接生成二進位制檔案test.o,沒有其他中間檔案生成

-g:包含除錯資訊

執行指令

 gcc -g test.c

可見不光生成了可執行檔案a.out,同時還在當前資料夾下生成了具備除錯資訊的檔案a.out.dSYM,此時可以使用除錯工具gdb對可執行檔案進行除錯

-I:指定include包含檔案的搜尋目錄

執行指令

gcc -I include/  -c test.c

表明在gcc執行過程中,除了標準庫中的標頭檔案,還可以從指定的目錄去搜索標頭檔案

-o:輸出成指定檔名

執行指令

gcc -o b test.c

表明指定生成的二進位制檔名稱為b,之後執行程式b,和a.out執行是同樣的結果

-lpthread:多執行緒程式設計

執行指令

gcc test.c -lpthread

指明gcc在連結階段連結pthread庫,從而編譯包含多執行緒標頭檔案的程式

-lm:程式使用了math.h中宣告的庫函式

執行指令

gcc test.c -lm

高階選項

-v:詳細輸出編譯過程中所採用的每一個選項

執行指令

gcc -v

得到結果

Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/4.2.1
Apple clang version 12.0.5 (clang-1205.0.22.11)
Target: x86_64-apple-darwin20.5.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

-C:預處理時保留註釋資訊

執行指令

gcc -E -C test.c 

得到結果

* Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. The rights granted to you under the License
 * may not be used to create, or enable the creation or redistribution of,
 * unlawful or unlicensed copies of an Apple operating system, or to
 * circumvent, violate, or enable the circumvention or violation of, any
 * terms of an Apple operating system software license agreement.
 *
 * Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this file.
																			.
                                      .
void clearerr(FILE *);
int fclose(FILE *);
int feof(FILE *);
int ferror(FILE *);
int fflush(FILE *);
int fgetc(FILE *);
int fgetpos(FILE * restrict, fpos_t *);
char *fgets(char * restrict, int, FILE *);
																			.
                                      .
                                      .

可見和單純執行-E選項時相比,還多加了註釋資訊

-ggdb:在可執行檔案中包含可供GDB使用的除錯資訊

-g選項和-ggdb選項只有細微的差別:

-g以OS本地格式(stabs,COFF,XCOFF或DWARF 2)產生除錯資訊。

-ggdb生成專門用於gdb的除錯資訊。

-fverbose-asm:在編譯成組合語言時,把C變數的名稱作為組合語言中的註釋

執行指令

gcc test.c -S -fverbose-asm

得到結果

 	.section	__TEXT,__text,regular,pure_instructions
	.build_version macos, 11, 0	sdk_version 11, 3
	.globl	_main                           ## -- Begin function main
	.p2align	4, 0x90
_main:                                  ## @main
	.cfi_startproc
## %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	subq	$16, %rsp
	movl	$0, -4(%rbp)
	movl	$0, -8(%rbp)
	movl	$1, -12(%rbp)
	leaq	L_.str(%rip), %rdi
	movb	$0, %al
	callq	_printf
	xorl	%ecx, %ecx
	movl	%eax, -16(%rbp)                 ## 4-byte Spill
	movl	%ecx, %eax
	addq	$16, %rsp
	popq	%rbp
	retq
	.cfi_endproc
                                        ## -- End function
	.section	__TEXT,__cstring,cstring_literals
L_.str:                                 ## @.str
	.asciz	"hello\n"

.subsections_via_symbols

-save-temps:自動輸出預處理檔案、彙編檔案、物件檔案,編譯正常進行

執行指令

gcc -save-temps test.c

之後使用ls命令檢視目錄中檔案狀態

a.out   test.bc test.c  test.i  test.o  test.s

可見保留了所有的中間檔案

-fsyntax-only:只測試原始檔語法是否正確,不會進行任何編譯操作

執行指令

gcc -fsyntax-only test.c

當原始檔沒有語法錯誤時,沒有任何輸出,當故意修改出一處語法錯誤時,得到結果

test.c:4:21: error: expected ';' at end of declaration
    int i = 0, j = 1 printf("hello\n");
                    ^
                    ;
1 error generated.

顯示出原始檔語法中存在的錯誤

-llibrary:連線時搜尋指定的函式庫

例如:多執行緒程式設計例子

gcc test.c -lpthread

-Idirectory:指定額外的標頭檔案搜尋路徑

例如:

gcc -I ../include test.c

新增目錄../include為標頭檔案搜尋路徑

-Ldirectory:指定額外的函式庫搜尋路徑

例如:

gcc -L ../lib test.c

新增目錄../iib為函式庫搜尋路徑

-static:禁止使用動態庫

詳見下節

-shared:儘量使用動態庫

詳見下節

庫的建立與使用

靜態庫

以建立靜態庫static_lib.a為例

1、編寫C原始檔static_lib.c,其中寫入需要重複呼叫的函式,執行命令

gcc -c static_lib.c

生成目標檔案static_lib.o

2、使用ar工具建立靜態庫

ar rcs static_lib.a static_lib.o

3、編寫C標頭檔案static_lib.h,其中寫入這些函式的原型宣告

4、編寫主函式app.c,引入標頭檔案static_lib.h,這樣就可以正常使用那些自定義的可複用函數了

5、執行命令

gcc app.c -static ./static_lib.a -o app

編譯生成可執行檔案app

動態庫

以建立動態庫share_lib.so為例

1、編寫C原始檔share_lib.c,寫入需要重複呼叫的函式,執行命令

gcc -shared -fPIC -o share_lib.so share_lib.c

生成動態庫檔案share_lib.so

2、編寫C標頭檔案share_lib.h,寫入函式的原型宣告

3、編寫主函式app.c,引入標頭檔案share_lib.h,之後就可以呼叫在動態庫中自定義的函數了

4、執行命令

gcc app.c ./share_lib.so -o app

編譯生成可執行檔案app

出錯提示選項

-Wall:會開啟一些很有用的警告選項,建議編譯時加此選項。

-W
-Wextra:列印一些額外的警告資訊。

-w:禁止顯示所有警告資訊。

-Wshadow:當一個區域性變數遮蓋住了另一個區域性變數,或者全域性變數時,給出警告。很有用的選項,建議開啟。 -Wall 並不會開啟此項。

-Wpointer-arith:對函式指標或者void *型別的指標進行算術操作時給出警告。也很有用。 -Wall 並不會開啟此項。

-Wcast-qual:當強制轉化丟掉了型別修飾符時給出警告。 -Wall 並不會開啟此項。

-Waggregate-return:如果定義或呼叫了返回結構體或聯合體的函式,編譯器就發出警告。

-Winline:無論是宣告為 inline 或者是指定了-finline-functions 選項,如果某函式不能內聯,編譯器都將發出警告。如果你的程式碼含有很多 inline 函式的話,這是很有用的選項。

-Werror:把警告當作錯誤。出現任何警告就放棄編譯。

-Wunreachable-code:如果編譯器探測到永遠不會執行到的程式碼,就給出警告。也是比較有用的選項。

-Wcast-align:一旦某個指標型別強制轉換導致目標所需的地址對齊增加時,編譯器就發出警告。

-Wundef:當一個沒有定義的符號出現在 #if 中時,給出警告。

-Wredundant-decls:如果在同一個可見域內某定義多次宣告,編譯器就發出警告,即使這些重複宣告有效並且毫無差別。

gcc常見警告含義

unused-function:警告宣告但是沒有定義的static函式;
unused- label:宣告但是未使用的標籤;
unused-parameter:警告未使用的函式引數;
unused-variable:宣告但是未使用的本地變數;
unused-value:計算了但是未使用的值;
format:printf和scanf這樣的函式中的格式字串的使用不當;
implicit-int:未指定型別;
implicit-function:函式在宣告前使用;
char- subscripts:使用char類作為陣列下標(因為char可能是有符號數);
missingbraces:大括號不匹配;
parentheses: 圓括號不匹配;
return-type:函式有無返回值以及返回值型別不匹配;
sequence-point:違反順序點的程式碼,比如 a[i] = c[i++];
switch:switch語句缺少default或者switch使用列舉變數為索引時缺少某個變數的case;
strict- aliasing=n:使用n設定對指標變數指向的物件型別產生警告的限制程度,預設n=3;只有在-fstrict-aliasing設定的情況下有效;
unknow-pragmas:使用未知的#pragma指令;
uninitialized:使用的變數為初始化,只在-O2時有效;

其它選項

語言標準

-ansi:ANSI標準
-std=c99:C99標準
-std=gnu89:ISO/IEC 9899:1990 以及GNU擴充
-std=gnu99:ISO/IEC 9899:1999 以及GNU擴充
-trigraphs:支援ISO C三字元組

優化選項

-O0:關閉所有優化選項
-O1:第一級別優化,使用此選項可使可執行檔案更小、執行更快,並不會增加太多編譯時間,可以簡寫為-O
-O2:第二級別優化,採用了幾乎所有的優化技術,使用此選項會延長編譯時間
-O3:第三級別優化,在-O2的基礎上增加了產生inline函式、使用暫存器等優化技術
-Os:此選項類似於-O2,作用是優化所佔用的空間,但不會進行效能優化,常用於生成最終版本

自定義副檔名

-x:使用此選項可以指定自定義的原始檔副檔名,型別有c、c-header、cpp-output、assembler、assembler-with-cpp、none

凡-x後面所列的所有檔案都會被視為其指定的型別,要想改變型別可以再一次使用-x選項,或者使用-x none回到預設設定

示例:gcc -o test test.c -x assembler test.asm -x c test2.c