最近在用GCC的時候,發現其中的一些命令選項可以幫助我解決這個問題。基本的思想是讓GCC在編譯的時候不刪除臨時文件,而這些臨時文件就包含了經過預處理之後的代碼,這時候就不會有宏的干擾了,但是也失去了宏原本的意義(比如說某些常量,使用宏的話,可以見名知義)。舉個例子來說,我們有這麼一個C程序a.c
int main(int argc, char *argv[])
{
int arch;
#ifdef _I386_
arch = 1;
#elif _MIPS_
arch = 2;
#elif _ARM_
arch = 3;
#else
#error "Give me a architecture select!"
#endif
return 0;
}
這時候-save-temps選項告訴gcc在編譯的過程中不要刪除臨時文件,那麼在當前文件夾下就會產生:
1)a.i : 是經過C預處理程序(CPP)處理之後的文件,這個就是我們以後工作的基礎
2)a.s: 是經過彙編器處理之後產生的彙編代碼
3)a.o: 是編譯器產生的目標代碼
4)a.out: 是編譯器默認產生的可執行程序。
我們主要在a.i的上面進行操作,如果我們想看MIPS平臺相關的代碼,我們就使用上面的命令產生a.i,我們來看a.i的內容, 由於內容比較多,我這裏只給出前10行和主體代碼部分:
# 1 "<built-in>"
# 1 "<command line>"
# 1 "a.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 28 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/features.h" 1 3 4
# 329 "/usr/include/features.h" 3 4
# 1 "/usr/include/sys/cdefs.h" 1 3 4
# 313 "/usr/include/sys/cdefs.h" 3 4
...............................
# 850 "/usr/include/stdio.h" 3 4
# 2 "a.c" 2
int main(int argc, char *argv[])
{
int arch;
arch = 2;
return 0;
}
1) #include 語句會被擴展開來,並把對應內容包含進來,同時加入 “# _line_number "_include_file_name_
" xx xx" 這些信息
2) 源文件當中的信息會有所保留,宏被展開,註釋被換成空行。條件宏起作用,其所在的行被換成空行。
我們要做的就是把這些以#號開頭的行和所有空行刪除,並重新對a.i文件進行排版,那麼它成了一個我們希望要的經過宏展開之後的C文件。
如果文件數目不多,我們可以使用這個命令 $ gcc -D_MIPS_ -E -P a.c >t.c 來實現上述功能,這個命令就是告訴GCC只進行預編譯,並且在預編譯的時候不產生“#include"語句和一些不必要的空行。但是當文件很多,特別是我們使用Makefile文件來控制我們整個工程的編譯的時候,這個方法就不合適了,就需要使用我前面提到的第
一種方法,具體做法如下:
1) 在Makfile文件當中的CFLAGS定義你想要的宏,並加上-save-temps選項,對於我們這個例子,我們可以定義: CFLAGS +=-D_MIPS -save-temps,然後執行make命令。執行成功之後,會生成一堆的 .i文件,下一步我麼要操作.i文件。
2)執行這麼一個腳本,它的作用就是把當前目錄下的所有以.i作爲後綴名的文件當中的 “#include" 行和空行刪除。
#filename: clearify.sh
for f in ./*.i
do
name=`basename $f`
sed "/^[[:space:]]*$/d" $name >t1
sed "/^# .*$/d" t1 >$name
done
希望對大家閱讀含有很多宏的源碼時有所幫助。