gcc -E -o out_file.i in_file.c
Do preprocessing
-D name
Predefine name as a macro, with definition 1.
將多個敘述句(statement)視為一個運算式(expression), 且最後一個物件應該為一個expression
跟著一個分號(;),這個subexpression的值代表整個construct的值
foo()
的結果的絕對值:
變數
z
的值即為foo()
的結果的絕對值 若改用大小括號( )取代分號(;), 則此construct的type為void
,表示沒有值 (no value)
statement expression
, 請參考"C99 - keywords/notes"中巨集
的閱讀筆記This feature is especially useful in making macro definitions “safe” (so that they evaluate each operand exactly once). For example, the “maximum” function is commonly defined as a macro in standard C as follows:
But this definition computes either a or b twice, with bad results if the operand has side effects.
在
K&R C 2nd
4.11.2 Macro Substitution有提及此陷阱(pitfall)及範例,如下:
方法1
: 透過GCC
提供的-E
option,只做preprocessing,來觀察macro置換的結果 (ref.):
Command:
方法2
: 透過GDB
的macro
command
GDB doc ref.: 12 C Preprocessor Macros
步驟如下:
Now, we compile the program using the GNU C compiler, GCC. We pass the -gdwarf-214 and -g3 flags to ensure the compiler includes information about preprocessor macros in the debugging information.
$ gcc -gdwarf-2 -g3 macro_eval_twice.c -o macro_eval_twice
Now, we start GDB on our sample program:
$ gdb -nw ./macro_eval_twice
We can expand macros and examine their definitions, even when the program is not running.
使用gdb
的過程如下:
從18, 19行的指令跟結果,可以觀察到跟方法1一樣置換後的結果;但無法觀察macro中expression的值,e.g. (2) > (3)?, 故,我將macro expand的結果拆解成
if statement
及expression
, 其中expression用來做increment;並觀察執行該if statement
前中後的變數的值的變化。從原始碼擷取上述說明對應的程式碼如下:
可以觀察到,執行完if statement判斷後,i與j會被累加,接著,進到if statement後,會再執行(i++);
,使得數值較大的變數會再被累加一次;如最後的warning message, 較大的值會從(3)變成(5)
關於第一個問題,
此document page給的範例為:
#define max(a,b) ((a) > (b) ? (a) : (b))
同上原始碼,有提供對應的程式碼來觀察此document給的範例:請參考goto
label TEST_MACRO_SAFE
至 END_OF_TEST
的程式碼; 這裡列出執行結果如下:
每個運算元只有被求值(evaluate)一次;上一個"unsafe"的例子,因為求值兩次,產生旁效應(side effect)
Note that introducing variable declarations (as we do in maxint) can cause variable shadowing
variable shadowing
的說明,請參考自我練習K&R C Exercise 4-14的實作。such as the value of an enumeration constant, the width of a bit-field, or the initial value of a static variable.
calls foo and bar1 and does not call baz but may or may not call bar2. If bar2 is called, it is called after foo and before bar1.
ref. 3.1 creating object files in Libtool
To create an object file from a source file, the compiler is invoked with the -c flag (and any other desired flags):
burger$ gcc -g -O -c main.c