[英]How does the pre-processor work in the following example?
在以下示例中:
#define PRNT(x, y) printf("X is %s and Y is %s\n", #x, #y)
int main(void)
{
PRNT("HELLO", 4);
}
這給出了:
X 是“你好”,Y 是 4
預處理器如何在上面進行替換? 例如,它為什么不評估為:
printf("X is %s and Y is %s\n", #x, #y)
printf("X is %s and Y is %s\n", "Hello", 4)
X is Hello and Y is 4\n
<-- HELLO
不是"HELLO"
那么它如何/為什么在 HELLO 周圍添加額外的"
;也就是說,為什么它打印..."HELLO"...
而不僅僅是...HELLO...
?將這兩個參數傳遞給printf
function 時,它最終變為\"
\"HELLO\"
和"4"
?
這對於x, y
是正確的,但不是#x, #y
使用“stringizing”修飾符。
如果你對一個字符串進行字符串化,你只會得到一個字符串,但它會包含周圍的引號。 如果對數字進行字符串化,則會得到一個字符串。
一般來說,對於給定的x
你會得到"x"
,所以對於"x"
你會得到"\"x\""
。
預處理器是否將字符串中的引號翻譯成
\"
,因此在將這兩個 args 傳遞給 printf function 時,它最終會變成\"HELLO\"
和"4"
?
是的。
如果您樂於接受 Microsoft 文檔, 請參閱此處:
此外,如果參數中包含的字符在字符串文字中使用時通常需要轉義序列,例如引號 (") 或反斜杠 (\) 字符,則會在字符之前自動插入必要的轉義反斜杠。
或者,如果您更喜歡更正式的版本,以下是C11(草案)標准的內容:
6.10.3.2 # 運算符
…
2 語義
... 否則,參數中每個預處理標記的原始拼寫將保留在字符串文字中,但產生字符串文字和字符常量的拼寫的特殊處理除外:在每個字符的 " 和 \ 字符之前插入一個 \ 字符常量或字符串文字(包括分隔的 " 字符),...
#X
給出了一個字符串文字,其內容是 X。所以帶有參數"FOO"
的#
給出了一個字符串文字,其五個字符是"
, F
, O
, O
, "
。 (當然還有 null 終結者)
預處理發生在代碼被標記和轉義序列處理之后,預處理的結果是一個標記 stream(不是某種需要重新標記和重新轉義處理的源文件)。
"HELLO"
是您傳遞給宏的令牌。 #
運算符將其轉換為字符串,因此您的字符串將為 "\"HELLO\"",就像您傳入數字4
時,它變為"4"
。 因此,當預處理器運行時,我希望您的代碼如下所示:
int main(void)
{
printf("X is %s and Y is %s\n", "\"HELLO\"", "4");
}
這樣做是因為宏內部變量前面的“#”。 它被稱為“字符串化”操作符,它將接受輸入變量,然后,將其字符串化。 這意味着在它周圍加上引號,以及已經在變量中的 escaping 。 這意味着,當展開時, "Hello"
變成"\"Hello\""
並且4
變成"4"
。
字符串化(當您在宏中執行#x
之類的操作時會發生什么)獲取項目並將其轉換為字符串。 在4
的情況下,你會得到"4"
,在"HELLO"
的情況下,你會得到"\"HELLO\""
,因為這兩個都是在打印項目時復制項目所需的確切字符串,因為例子。
許多編譯器可以選擇在預處理后停止以允許您檢查其效果,例如使用gcc
的-E
標志:
pax:~> gcc --std=c17 -E prog.c
# 1 "prog.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "prog.c"
int main(void)
{
printf("X is %s and Y is %s\n", "\"HELLO\"", "4");
}
#x
將x
轉換為字符串。
IE
x = "Hello"
然后
#x = "\"Hello\""
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.