取下面的代碼
union vec
{
struct
{
float x, y, z;
};
float data[3];
constexpr vec() : data{} {}
};
constexpr vec make_vec(float x, float y, float z)
{
vec res;
res.data[0] = x;
res.data[1] = y;
res.z = z;
return res;
}
int main()
{
constexpr vec out = make_vec(0, 1, 2);
std::cout << out.z << '\n';
}
我在這里使用 constexpr 來確定代碼是否是未定義的行為,因為未定義的行為會導致編譯錯誤。
§9.2/19:
如果一個標準布局聯合包含兩個或多個共享一個公共初始序列的標準布局結構,并且如果標準布局聯合物件當前包含這些標準布局結構之一,則允許檢查任何的公共初始部分其中。
由此,我假設代碼中的所有內容都將被定義為行為。
用 編譯g main.cpp -o out -std=c 17,我得到訊息error: change of the active member of a union from 'vec::data' to 'vec::<anonymous>'。
我以為要符合標準,我可能不得不把它改成這樣——
union vec
{
struct
{
float x, y, z;
};
struct
{
float data[3];
};
constexpr vec() : data{} {}
};
但我得到同樣的錯誤。
這真的是未定義的行為嗎?我可能錯過了標準的另一部分,還是我只是誤解了標準?
uj5u.com熱心網友回復:
是的,這是UB。
在你寫信給float data[3];工會的一部分后,你就不能再讀了struct { float x, y, z; };
就這么簡單。
共享一個共同的初始序列
不涵蓋這兩個,因為陣列與一個浮點數后跟另一個浮點數不同。
重要編輯
上面的答案假設代碼是 UB,因為.xand.y成員無效。正如@user17732522 指出的那樣。它比這更微妙一些。
.x并且.y回傳未初始化并且將具有未定義的值。但是對成員的寫入.z確實設定了工會的活躍成員。因此,只要呼叫代碼只讀取.z成員,一切都是定義和正確的。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/517236.html
