[英]When is the compiler allowed to optimize away a validity check of an enum or enum class type value in C++?
在尋找上述問題的答案時,我遇到了 Luke Kowald 對問題Check if a value is defined in an C enum?的回答。 . 它指出,可以通過檢查某個值是否等於開關中的可能值之一來檢查該值是否對枚舉有效。
typedef enum {
MODE_A,
MODE_B,
MODE_C
}MODE;
int modeValid(int mode)
{
int valid = 0;
switch(mode) {
case MODE_A:
case MODE_B:
case MODE_C:
valid = 1;
};
return valid;
}
假設值int mode
在檢查它是否有效之前已轉換為類型MODE
:
int modeValid(MODE mode)
{
int valid = 0;
switch(mode) {
case MODE_A:
case MODE_B:
case MODE_C:
valid = 1;
};
return valid;
}
這仍然可以保證工作還是編譯器可以將檢查優化為始終為真,因為枚舉不應具有除檢查值以外的值?
在枚舉類的情況下,這將如何表現?
C 2018 草案 N4659 10.2(“枚舉聲明”,[dcl.enum])8 告訴我們枚舉類型的值是什么。 我將在下面引用它,但它本質上是這樣說的:
該段落明確指出“可以定義一個枚舉,其值未被任何枚舉器定義。”
因此,除非命名枚舉器填充枚舉類型的范圍,否則MODE
類型的mode
對象可能具有不是MODE
類型的命名枚舉器值之一的值。 將值轉換為MODE
類型並不能確保結果具有指定枚舉器之一的值。
對於底層類型固定的枚舉,枚舉的值就是底層類型的值。 否則,對於e min是最小枚舉數而e max是最大枚舉數的枚舉,枚舉值是b min到b max范圍內的值,定義如下: 對於二進制補碼表示,設K為 1 和0 表示一個的補碼或符號幅度表示。 b max是大於或等於 max(|e min | − K , | e max |) 且等於 2 M − 1 的最小值,其中M是非負整數。 如果e min為非負,則b min為零,否則為 -( b max + K )。 如果b min為零,則足以容納枚舉類型的所有值的最小位字段的大小為 max( M , 1) ,否則為M + 1。 可以定義一個枚舉,它的值不是由它的任何枚舉器定義的。 如果 enumerator-list 為空,則枚舉的值就好像該枚舉具有值為 0 的單個枚舉器。
這仍然可以保證工作嗎
是的。
沒有規則禁止像這樣調用函數:
modeValid(static_cast<MODE>(42));
並且因為這與任何案例標簽都不匹配,所以行為必須是返回 0。
編譯器是否可以將檢查優化為始終為真,因為枚舉不應具有除檢查值以外的值?
假設規則適用。 如果編譯器可以證明觀察到的行為符合規定,那么是。 例如,當使用編譯時常量參數內聯擴展函數調用時,就會出現這種情況。
在枚舉類的情況下,這將如何表現?
相同的。
標准規則(來自最新的 C++ 草案):
枚舉的值是基礎類型的值:
[dcl.enum]
對於底層類型固定的枚舉,枚舉的值就是底層類型的值。 否則,枚舉的值是可由具有最小寬度 M 的假設整數類型表示的值,以便可以表示所有枚舉數。 ...
底層類型是一個整數類型:
[dcl.enum]
每個枚舉定義了一個不同於所有其他類型的類型。 每個枚舉也有一個基礎類型。 可以使用 enum-base 顯式指定基礎類型。 對於作用域枚舉類型,如果未明確指定,基礎類型為 int。 在這兩種情況下,底層類型都被認為是固定的。 ...
雖然 enum 具有命名值,但它也可以保存基礎類型的所有其他值。 同樣適用於enum class
。 這是完全合法的:
enum Color { red = 0xFF0000, green = 0x00FF00, blue = 0x0000FF };
int main() {
Color buttonColor = static_cast<Color>(red | green); // yellow
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.