![](/img/trans.png)
[英]Why can't C++11 strongly-typed enum be cast to underlying type via pointer?
[英]Is it safe to convert a pointer to typed/sized enum to a pointer to the underlying type?
以下代碼:
void f(const uint8_t* a) {} // <- this is an external library function
enum E : uint8_t { X, Y, Z };
int main(void) {
E e = X;
f(&e); // <- error here
}
產生以下錯誤:
/tmp/c.cc:10:3: error: no matching function for call to 'f'
f(&e);
^
/tmp/c.cc:5:6: note: candidate function not viable: no known conversion from 'E *' to 'const uint8_t *' (aka 'const unsigned char *') for 1st argument
void f(const uint8_t* e) { }
這對我來說是令人驚訝的,因為我認為: uint8_t
enum定義中的: uint8_t
意味着它們必須用底層類型表示。 我可以通過演員輕松解決這個問題:
f((uint8_t*)&e);
我不介意太多,但鑒於省略它是一個錯誤,這是永遠安全還是: uint8_t
不提供我認為的保證?
它確實是安全的(雖然我不是語言律師):存儲在內存中的是uint8_t
,這就是你要指出的內容。 但是,如果f()
要指向非const uint8_t
,那么它可能會將值更改為未明確定義為E
enum值之一的值。 (編輯:)雖然這顯然是C ++標准所允許的,但對於許多人來說這是令人驚訝的(參見下面關於這一點的評論中的討論),我鼓勵你確保它不會發生。
...但正如其他人所說,由於你的安全概念,你沒有得到錯誤,而是因為在指向類型之間不執行隱式轉換。 您可以將一個E
傳遞給一個函數,該函數將uint8_t
,而不是E *
傳遞給一個取uint8_t *
的函數; 那將是 - 根據語言委員會和我認為 - 對指針類型過於傲慢的態度。
Afaik這只是偶然合法的:
你正在做的是執行reinterpret_cast
,我假設f
在內部取消引用該指針。 這在一組非常有限的案例中是合法的,雖然不是規范性的,但cppreference.com給出了很好的概述:
當動態類型為DynamicType的對象的指針或引用是reinterpret_cast(或C樣式轉換)為指針或對不同類型AliasedType的對象的引用時,轉換總是成功,但結果指針或引用可能僅用於如果滿足以下條件之一,則訪問該對象:
AliasedType是(可能是cv限定的)DynamicType
AliasedType和DynamicType都是(可能是多級,可能在每個級別的cv限定)指向相同類型T的指針(自C ++ 11以來)
AliasedType是DynamicType的(可能是cv限定的)有符號或無符號變體
AliasedType是一種聚合類型或聯合類型,它將上述類型之一保存為元素或非靜態成員(包括,遞歸地,包含聯合的子聚合和非靜態數據成員的元素):這樣可以安全地獲取給定指向其非靜態成員或元素的指針的結構或聯合的可用指針。
AliasedType是DynamicType的(可能是cv限定的)基類,DynamicType是沒有非靜態數據成員的標准布局類,AliasedType是它的第一個基類。
AliasedType是char,unsigned char或std :: byte:這允許將任何對象的對象表示檢查為字節數組。
如果AliasedType不滿足這些要求,則通過新指針或引用訪問對象會調用未定義的行為。 這稱為嚴格別名規則,適用於C ++和C編程語言。
這些情況都不包括轉換為指向枚舉的基礎類型的指針!
然而:
轉換為指向unsigned char*
的指針並取消引用它總是合法的,在大多數平台上, uint8_t
只是一個typedef。 所以在這種情況下是可以的,但如果基礎類型例如是uint16_t
不會。
話雖如此,聽到大多數編譯器允許這樣的使用,即使標准沒有這樣,我也不會感到驚訝。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.