參見:html
https://gcc.gnu.org/onlinedocs/cpp/index.htmlvim
#表示將其後的內容轉換爲字符串,##表示將它先後兩個TOKEN鏈接爲一個。app
3.4 Stringification Sometimes you may want to convert a macro argument into a string constant. Parameters are not replaced inside string constants, but you can use the ‘#’ preprocessing operator instead. When a macro parameter is used with a leading ‘#’, the preprocessor replaces it with the literal text of the actual argument, converted to a string constant. Unlike normal parameter replacement, the argument is not macro-expanded first. This is called stringification. There is no way to combine an argument with surrounding text and stringify it all together. Instead, you can write a series of adjacent string constants and stringified arguments. The preprocessor will replace the stringified arguments with string constants. The C compiler will then combine all the adjacent string constants into one long string. Here is an example of a macro definition that uses stringification: #define WARN_IF(EXP) \ do { if (EXP) \ fprintf (stderr, "Warning: " #EXP "\n"); } \ while (0) WARN_IF (x == 0); ==> do { if (x == 0) fprintf (stderr, "Warning: " "x == 0" "\n"); } while (0); The argument for EXP is substituted once, as-is, into the if statement, and once, stringified, into the argument to fprintf. If x were a macro, it would be expanded in the if statement, but not in the string. The do and while (0) are a kludge to make it possible to write WARN_IF (arg);, which the resemblance of WARN_IF to a function would make C programmers want to do; see Swallowing the Semicolon. Stringification in C involves more than putting double-quote characters around the fragment. The preprocessor backslash-escapes the quotes surrounding embedded string constants, and all backslashes within string and character constants, in order to get a valid C string constant with the proper contents. Thus, stringifying p = "foo\n"; results in "p = \"foo\\n\";". However, backslashes that are not inside string or character constants are not duplicated: ‘\n’ by itself stringifies to "\n". All leading and trailing whitespace in text being stringified is ignored. Any sequence of whitespace in the middle of the text is converted to a single space in the stringified result. Comments are replaced by whitespace long before stringification happens, so they never appear in stringified text. There is no way to convert a macro argument into a character constant. If you want to stringify the result of expansion of a macro argument, you have to use two levels of macros. #define xstr(s) str(s) #define str(s) #s #define foo 4 str (foo) ==> "foo" xstr (foo) ==> xstr (4) ==> str (4) ==> "4" s is stringified when it is used in str, so it is
3.5 Concatenation It is often useful to merge two tokens into one while expanding macros. This is called token pasting or token concatenation. The ‘##’ preprocessing operator performs token pasting. When a macro is expanded, the two tokens on either side of each ‘##’ operator are combined into a single token, which then replaces the ‘##’ and the two original tokens in the macro expansion. Usually both will be identifiers, or one will be an identifier and the other a preprocessing number. When pasted, they make a longer identifier. This isn't the only valid case. It is also possible to concatenate two numbers (or a number and a name, such as 1.5 and e3) into a number. Also, multi-character operators such as += can be formed by token pasting. However, two tokens that don't together form a valid token cannot be pasted together. For example, you cannot concatenate x with + in either order. If you try, the preprocessor issues a warning and emits the two tokens. Whether it puts white space between the tokens is undefined. It is common to find unnecessary uses of ‘##’ in complex macros. If you get this warning, it is likely that you can simply remove the ‘##’. Both the tokens combined by ‘##’ could come from the macro body, but you could just as well write them as one token in the first place. Token pasting is most useful when one or both of the tokens comes from a macro argument. If either of the tokens next to an ‘##’ is a parameter name, it is replaced by its actual argument before ‘##’ executes. As with stringification, the actual argument is not macro-expanded first. If the argument is empty, that ‘##’ has no effect. Keep in mind that the C preprocessor converts comments to whitespace before macros are even considered. Therefore, you cannot create a comment by concatenating ‘/’ and ‘*’. You can put as much whitespace between ‘##’ and its operands as you like, including comments, and you can put comments in arguments that will be concatenated. However, it is an error if ‘##’ appears at either end of a macro body. Consider a C program that interprets named commands. There probably needs to be a table of commands, perhaps an array of structures declared as follows: struct command { char *name; void (*function) (void); }; struct command commands[] = { { "quit", quit_command }, { "help", help_command }, ... }; It would be cleaner not to have to give each command name twice, once in the string constant and once in the function name. A macro which takes the name of a command as an argument can make this unnecessary. The string constant can be created with stringification, and the function name by concatenating the argument with ‘_command’. Here is how it is done: #define COMMAND(NAME) { #NAME, NAME ## _command } struct command commands[] = { COMMAND (quit), COMMAND (help), ... };
註釋:ide
##表示將它先後兩個TOKEN鏈接爲一個,如下三種結果爲:函數
1. #define YNAME(n) y_##n_Y, 則YNAME(1),表示變量y_n_Yui
2. #define YNAME(n) y_n##_Y, 則YNAME(1),表示變量y_n_Ythis
3. #define YNAME(n) y_##n##_Y, 則YNAME(1),表示變量y_1_Yspa
例如#define VAL 352*288,當c語言函數調用VAL時,是使用352*288,仍是101376哪?翻譯
咱們知道GCC編譯源代碼生成最終可執行的二進制程序,GCC後臺隱含執行了四個階段步驟。
GCC編譯C源碼有四個步驟:預處理-----> 編譯 ----> 彙編 ----> 連接
如今咱們就用GCC的命令選項來逐個剖析GCC過程。code
#include <stdio.h> #define VAL 352*288 int main(void) { printf("val:%d\n", VAL); return 1; }
1)預處理(Pre-processing)
在該階段,編譯器將C源代碼中的包含的頭文件如stdio.h編譯進來,用戶能夠使用gcc的選項」-E」進行查看。
用法:#gcc -E test_macro.c -o test_macro.i
做用:將test_macro.c預處理輸出test_macro.i文件。
vim test_macro.i
int main(void) { printf("val:%d\n", 352*288); return 0; }
註釋:VAL被替換爲352*288
2)編譯階段(Compiling)
第二步進行的是編譯階段,在這個階段中,Gcc首先要檢查代碼的規範性、是否有語法錯誤等,以肯定代碼的實際要作的工做,在檢查無誤後,Gcc把代碼翻譯成彙編語言。用戶能夠使用」-S」選項來進行查看,該選項只進行編譯而不進行彙編,生成彙編代碼。
選項 -S
用法:[root]# gcc -S test_macro.i -o test_macro.s
做用:將預處理輸出文件 test_macro .i彙編成 test_macro .s文件。
vim test_macro .s
.file "test_macro.c" .section .rodata .LC0: .string "val:%d\n" .text .globl main .type main, @function main: .LFB0: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movl $.LC0, %eax movl $101376, %esi movq %rax, %rdi movl $0, %eax call printf movl $0, %eax leave .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size main, .-main .ident "GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-16)" .section .note.GNU-stack,"",@progbits
註釋:VAL的值爲101376,即爲352*288的結果
3)彙編階段(Assembling)
彙編階段是把編譯階段生成的」.s」文件轉成二進制目標代碼.
選項 -c
用法:[root]# gcc -c test_macro .s -o test_macro .o
做用:將彙編輸出文件 test_macro .s編譯輸出 test_macro .o文件。
4)連接階段(Link)
在成功編譯以後,就進入了連接階段。
無選項連接
用法:[root]# gcc test_macro.o -o test_macro.exe
做用:將編譯輸出文件 test_macro .o連接成最終可執行文件 test_macro .exe。
註釋:
宏定義的表達式在編譯階段進行計算。