2016-02-13 104 views
9

如果我將一個宏定義爲#define LOGIC_ONE 1並且想在case語句中使用LOGIC_ONE,那麼究竟是什麼類型的LOGIC_ONE宏是什麼類型的考慮?

是它識別爲int,因爲我定義它的值1?

+1

要查看預處理器不,傳給'-E'到編譯器的快捷方式。 (msvc,gcc,clang都接受'-E') – Ben

回答

19

C++宏是簡單的文本替換。

在編譯器啓動時,預編譯器已將LOGIC_ONE替換爲1。它就好像你會立刻寫上1一樣。 (在這種情況下,是文字的一個int ...)

編輯在意見討論:
如果您(或其他人訪問您的代碼)改變你#define LOGIC_ONE 1#define LOGIC_ONE "1"它會改變它在你的程序中的行爲,併成爲一個const char[]文字。

編輯:
由於這個帖子得到了更多的關注比我預期,我想我的引用添加到C++ 14 Standard對於那些好奇:

2.2階段的翻譯 [lex.phases]
(...)
4.執行預處理指令,展開宏調用,並執行 _Pragma一元運算符表達式。 (...)然後刪除所有預處理指令。
(...)
7.分隔標記的空白字符不再重要。每個預處理令牌都被轉換爲令牌。 (2.6)。所產生的令牌在語法和語義上被分析並翻譯爲翻譯單元。

如前所述,宏在階段4中被替換,之後不再存在。 「語法和語義」分析發生在階段7,代碼被編譯(「翻譯」)。

整數常量在

2.13.2整數常量指定 [lex.icon]
(...)
一個整數文字是具有無期或指數的數字序列部分,可選分隔單引號,在確定其值時會被忽略。整數文字可能有一個前綴,用於指定其基數和一個指定其類型的後綴。
(...)

表5 -

Suffix | Decimal literal  | Binary, octal, or hexadecimal literal 
----------------------------------------------------------------------------- 
none   | int     | int 
      | long int    | unsigned int 
      | long long int   | long int 
      |      | unsigned long int 
      |      | long long int 
      |      | unsigned long long int 
----------------------------------------------------------------------------- 
u or U  | unsigned int   | unsigned int 
      | unsigned long int  | unsigned long int 
      | unsigned long long int | unsigned long long int 
----------------------------------------------------------------------------- 
l or L  | long int    | long int 
      | long long int   | unsigned long int 
      |      | long long int 
      |      | unsigned long long int 
----------------------------------------------------------------------------- 
Both u or U | unsigned long int  | unsigned long int 
and l or L | unsigned long long int | unsigned long long int 
----------------------------------------------------------------------------- 
ll or LL  | long long int   | long long int 
             | unsigned long long int 
----------------------------------------------------------------------------- 
Both u or U |unsigned long long int | unsigned long long int 
and ll or LL |      | 

字符串文本在

2.13.5字符串文字 [lex.string]指定的整數文字的類型
(...)
1字符串文字是由雙引號括起來的一系列字符(如2.13.3中定義的),可選地以R,u8,u8R,u,uR,U,UR,L,rLR作爲前綴,如「 ...「,R」(...)「,u8」...「,u8R」**(...)**「,u」...「,uR」*〜(...) *「,U」...「,UR」zzz(...)zzz「,L」...「或LR」(...)「。
(...)
6翻譯階段6之後,不以編碼前綴開始的字符串文字是普通的字符串文字,並且使用給定的字符進行初始化。
7以u8開頭的字符串文字,例如u8「asdf」,是一個UTF-8字符串文字。
8普通字符串文字和UTF-8字符串文字也被稱爲窄字符串文字。窄字符串文字具有類型「n const char」的數組,其中n是如下定義的字符串的大小,並具有 靜態存儲持續時間(3.7)。

+0

I.e.我可以把'LOGIC_ONE'看作是一個'int'嗎? – Noobgineer

+0

@Noobgineer當前值是,但是如果有人將它改爲'「1」' –

+2

你可以用任何你可以對待'1'的方式來對待它 - 所以是的,它是一個整型文字。 – Anedar

8

LOGIC_ONE在任何地方都會被替換爲1。就編譯器而言,LOGIC_ONE不存在,它只是看到1.所以你的問題是'是1是一個int?'。答案就是 - >這取決於你在哪裏鍵入1

+0

好的。我不知道編譯器是尋找'1'還是'LOGIC_ONE'。謝謝你的澄清! – Noobgineer

6

宏是一個文本替換。 1類型爲constexpr int

11

預處理器定義沒有類型 - 它們基本上只是「粘貼」到它們出現的代碼中。例如,如果您在聲明中使用它,

int foo = LOGIC_ONE; 

然後它會被解釋爲整數。 (編譯器,在預處理器之後運行,只能看到代碼爲int foo = 1;)您甚至可以在一個糟糕的語句中使用它,例如;

int foo##LOGIC_ONE; 

然後,您將創建一個變量foo1。育!

舉一個宏定義的替代例子;

#define LOGIC_ONE hello 
int LOGIC_ONE = 5; 
printf("%d\n", hello); 

這是完全有效的,並宣佈名爲hello int,但表明,沒有「型」的定義 - hello只是被取代的地方LOGIC_ONE在代碼中遇到。

避免使用預處理器宏,除非絕對必要。專業編碼標準通常禁止或嚴格限制預處理器的使用。通常總是有比使用宏更好的方法來做事。例如,考慮這些替代方案;

static const int LOGIC_ONE = 1; 
enum { LOGIC_ONE = 1 }; 

預處理器是學習者在一個真正的混亂得到C.

+1

感謝您的詳細解釋。這些宏是作爲API的一部分提供的,我必須使用並且不允許修改,但是我會在避免預處理器宏的情況下爲您的未來努力提供建議! – Noobgineer

+0

我認爲令牌粘貼只適用於宏參數,並且一般不應用於宏? – supercat

+0

針對宏的非常有限使用的建議在C++中是10倍(這個問題被標記)。幾乎可以肯定,無論您使用宏都可以實現哪種安全方式,它都是更好的類型安全方法。文件包含,包括警衛和條件編譯是預處理的剩餘主要停留。 – Persixty

相關問題