[Mac 10.7.1 Lion Intel-based x64 gcc 4.2.1]
Q: 如何讓編譯的檔案可以被gdb調試?
A: 可以加入-g參數。如下代碼,儲存為hello.c:
#include <stdio.h>int main(){ printf("hello world!\n"); return 0;}
編譯 gcc hello.c -o hello得到hello.
使用 gdb hello進入調試,輸入list:
可以看到提示沒有符號被載入,這說明上面的編譯命令沒有加入調試資訊,不能被gdb正常調試。
加入-g參數重新編譯 gcc -g hello.c -o hello得到檔案hello.
gdb hello進入調試,輸入list:
可以看到,此時已經可以看到原始碼了,接著就可以調試了。
Q: 如何編譯器能讓gprof工具使用?
A: 使用-p參數。不過根據bug列表,intel架構的mac系統不能正常運行gprof, 以後將在ubuntu下將這個例子寫出來。
Q: 如果原始碼的副檔名不是gcc預設支援的副檔名,那麼編譯會出現什麼情況?
A: 將上面的hello.c複製一個為hello.xichen,使用gcc -o hello hello.xichen編譯:
可以看到出現了問題;可以使用-x參數將檔案當成指定類型的檔案來編譯:
gcc -x c hello.xichen -o hello是將hello.xichen當成c代碼編譯:
可以看出已經正確編譯了; -x參數後面可以跟隨c, c++等類型名, 也可以跟隨none來關閉指定為特定類型檔案編譯, 具體請參照gcc協助文檔。
Q: 如果需要測試代碼是否符合ansi標準,怎麼辦?
A: 可以使用-ansi參數。如果是c代碼,它對於不遵循c90標準的代碼將出現編譯問題。
對於//作為注釋,從c99才開始支援,用此作為測試。
#include <stdio.h>int main(){ // c99 support // style comment printf("hello world!\n"); return 0;}
儲存為hello.c:
gcc -ansi -o hello hello.c編譯:
使用gcc -o hello hello.c編譯:
可以看到,這樣就沒有問題。
Q: c語言有不同的標準,那麼設定遵循哪種標準使用什麼參數?
A: 可以使用-std=參數格式,可以跟隨c99, gnu99等參數。
Q: 如何禁止將某些關鍵字當做關鍵字?
A: 可以使用-fno-asm參數來禁止asm, inline, typeof當做關鍵字。如下代碼,儲存為hello.c:
#include <stdio.h>inline int add(int a, int b){ return a + b;}int main(){ printf("hello world!\n"); return 0;}
使用gcc -fno-asm hello.c -o hello編譯:
可以看到出現了編譯錯誤;使用gcc hello.c -o hello編譯:
Q: 有時,有的編譯器將char預設當做有符號的,有的當做無符號的,用編譯器參數可以實現自由控制嗎?
A: 是的。可以使用-funsigned-char或者-fno-signed-char來將char自動當做unsigned類型;類似的,用-fsigned-char或者-fno-unsigned-char來將char自動當做signed類型。例子如下,代碼儲存為unsigned_signed_char.c:
#include <stdio.h>int main(){ char ch = 0xFF; if(ch < 0) printf("char is signed...\n"); else printf("char is unsigned...\n"); return 0;}
使用gcc unsigned_signed_char.c -o unsigned_signed_char編譯運行:
使用gcc unsigned_signed_char.c -o unsigned_signed_char -funsigned-char編譯運行:
使用 gcc unsigned_signed_char.c -o unsigned_signed_char -fsigned-char來編譯運行:
Q: 如果有的時候在一個檔案中忘記包含了標頭檔,如何用編譯參數插入標頭檔呢?
A: 可以使用-include參數。代碼如下,儲存為no_header.c:
int main(){ fprintf(stdout, "no header file\n"); return 0;}
使用gcc no_header.c -o no_header編譯:
可以看到,編譯出錯了;改用gcc no_header.c -o no_header -include /usr/include/stdio.h編譯:
運行ok:
同樣,可以使用-DXXX或者-DXXX=YYY或者-UXXX或者-undef來定義宏擷取取消定義宏(XXX表示宏名, YYY表示宏定義的字串).
Q: 有時,有個宏在另外一個檔案中,想把它的值作用到另一個檔案中,如何做?
A: 可以使用-imacros 參數; -imacros後面跟著需要包含的宏名的檔案。如下代碼,儲存為imacros.h:
#ifndef IMACROS_H#define IMACROS_H#define N 100double add(double, double);#endif
如下代碼,儲存為imacros.c(它和上面的imacros.h在同一個目錄下):
#include <stdio.h>int add(int, int);int main(){ int i = N; printf("i is %d\n", i); return 0;}
可以看到imacros.c檔案中的N沒有被定義,imacros.h中有它的宏定義。使用gcc imacros.c -o imacros -imacros imacros.h編譯:
可以看到編譯ok,且imacros.h中的add函式宣告和imacros.c中的add函式宣告不一致的問題也沒有任何警告,因為-imacros僅僅將imacros.h檔案中的宏進行處理,其它沒有處理。
運行結果:
修改imacros.c代碼如下:
#include <stdio.h>#include "imacros.h"int add(int, int);int main(){ int i = N; printf("i is %d\n", i); return 0;}
採用gcc imacros.c -o imacros編譯:
可以看到,編譯出錯了,就是因為add聲明不一致導致的;這裡就可以看出-imacros參數的作用了。
Q: 如果有的時候,為了方便管理,將一些標頭檔移動到另一個目錄,代碼中的標頭檔路徑不想用絕對路徑,命令列參數該如何設定呢?
A: 可以使用-I參數來實現添加額外標頭檔路徑的方式。如下代碼,儲存為include_folder.c:
#include <stdio.h>int main(){ fprintf(stdout, "hello\n"); return 0;}
在hello.c的同目錄下建立如下檔案stdio.h:
#ifndef STDIO_H #define STDIO_H #endif
它基本沒什麼用途。
如果使用gcc include_folder.c -o include_folder編譯沒有任何問題。
如果使用gcc include_folder.c -o include_folder -I.編譯:
可以看出,編譯出了問題,因為-I.編譯參數將本目錄加入了標頭檔搜尋路徑, 而且是優先在-I指定的路徑下尋找,include_folder.c包含了stdio.h標頭檔,且優先在本目錄下尋找,包含了一個沒有任何用途的標頭檔,導致了後面的編譯錯誤。和-I參數對於標頭檔路徑修改類似的,還有-idirafter, -iprefix, -iwithprefix, -iwithprefixbefore參數。
Q: 如果一個makefile中在當時必須使用-I來包含指定的標頭檔路徑,但是後來因為一些原因又不能繼續使用,有命令可以解決這個問題嗎?
A: 是的。可以使用-I-來取消使用-I參數指定的額外的標頭檔路徑,不過這個參數形式以後可能會廢棄,建議採用-Iquote來代替它。如上面的代碼,使用gcc include_folder.c -o include_folder -I. -I-或者gcc include_folder.c -o include_folder -I. -iquote都可以正確編譯。
Q: 如果不想使用系統的標頭檔,想直接使用自己編寫的標頭檔,這些標頭檔被儲存在另一個目錄下,怎麼辦?
A: 如下代碼nostdinc.c:
#include <stdio.h>#include <stdlib.h>int main(){ int i = NOSTDINC; return 0;}
nostdinc.c同目錄下有個標頭檔stdio.h:
#ifndef STDIO_H #define STDIO_H #define NOSTDINC 99#endif
使用gcc nostdinc.c -o nostdinc -I. -nostdinc編譯:
可以看出,使用了-nostdinc參數,編譯器將不在系統標頭檔路徑下搜尋, -I.將使得它在本目錄下搜尋,結果沒找到stdlib.h標頭檔,報錯了;可以去掉-nostdinc參數選項,使用gcc nostdinc.c -o nostdinc -I.編譯即可:
或者nostdinc.c原始碼中將對stdlib.h標頭檔的包含代碼去掉也可以。
Q: 有時需要對原始碼進行預先處理,但是其中的注釋被刪除了,對於分析預先處理後代碼可能有影響,如何讓預先處理過程不刪除注釋?
A: 可以使用-C參數來實現,它一般都和-E參數搭配使用。如下代碼simple_hello.c:
int main(){ // just write something return 0;}
使用gcc -E simple_hello.c預先處理,得到內容:
# 1 "simple_hello.c"# 1 "<built-in>"# 1 "<command-line>"# 1 "simple_hello.c"int main(){ return 0;}
可以看到,注釋被刪除了。
如果採用gcc -C -E simple_hello.c預先處理,得到如下內容:
# 1 "simple_hello.c"# 1 "<built-in>"# 1 "<command-line>"# 1 "simple_hello.c"int main(){ // just write something return 0;}
可以發現注釋依然存在。
Q: 有時我需要查看一個原始碼的依賴關係,如何查看?
A: 可以使用-M參數來獲得。例如,如下代碼,儲存為hello.c:
#include <stdio.h>int main(){ printf("hello, xichen\n"); return 0;}
使用gcc -M hello.c得到內容:
hello.o: hello.c /usr/include/stdio.h /usr/include/sys/cdefs.h \ /usr/include/sys/_symbol_aliasing.h \ /usr/include/sys/_posix_availability.h /usr/include/Availability.h \ /usr/include/AvailabilityInternal.h /usr/include/_types.h \ /usr/include/sys/_types.h /usr/include/machine/_types.h \ /usr/include/i386/_types.h /usr/include/secure/_stdio.h \ /usr/include/secure/_common.h
可以看出,hello.c的依賴關係。
類似的還有-MD, -MM, -MMD參數。
Q: 如果希望將一個編譯選項傳遞給gcc內部調用的組譯工具或者連結程式,如何傳遞?
A: 可以使用-Wa,option的方式將option傳遞給組譯工具;可以使用-Wl,option的方式將option傳遞給連結程式。
Q: 有時,我需要產生stabs格式的調試資訊,如何產生?
A: 可以使用-gstabs命令得到,但是它不會產生gdb調試資訊,所以無法再用gdb對產生的可執行檔進行調試。類似的編譯參數還有-gstabs+, -ggdb.
Q: 如果希望使用靜態連結或者動態連結,或者產生一個共用庫,使用什麼參數?
A: 可以使用-static或者-shared參數。但是,在mac系統上,-static基本沒什麼用,-shared參數它不支援。
Q: 如何希望體驗古老的c語言的特性,可以使用什麼參數?
A: 可以使用-traditional參數。具體的例子筆者也寫不出來,寫了幾個看起來很古老的文法,結果gcc都正常給編譯通過了。
Q: 如果需要產生針對某個平台的最佳化代碼,如何辦?
A: 可以使用-O相關的參數進行最佳化,也可以使用-mtune=cpu_type進行具體平台最佳化。
Q: 如果需要不顯示警告資訊或者顯示所有能顯示的警告資訊,如何辦?
A: 可以使用-w參數或者-Wall參數。如下代碼,儲存為warning.c:
#include <stdio.h>void main(){ int i; printf("hello, xichen\n");}
使用gcc warning.c -o warning編譯:
使用gcc warning.c -o warning -Wall編譯:
可以看出,包括i沒有被使用的警告也被顯示出來;
使用gcc warning.c -o warning -w編譯:
可以看到沒有任何警告資訊顯示了。
xichen
2012-5-19 22:26:32