我正在維護一個舊代碼庫,即使用整數型別的聯合與位域結構進行型別雙關。我的編譯器是 VS2017。例如,代碼類似于以下內容:
struct FlagsType
{
unsigned flag0 : 1;
unsigned flag1 : 1;
unsigned flag2 : 1;
};
union FlagsTypeUnion
{
unsigned flagsAsInt;
FlagsType flags;
};
bool isBitSet(unsigned flagNum, FlagsTypeUnion flags)
{
return ((1u << flagNum) & flags.flagsAsInt);
}
此代碼有許多未定義的行為問題。即,關于型別雙關語是否是定義行為引起了激烈的爭論,但最重要的是,打包位欄位的實作是實作定義的。為了解決這些問題,我想添加靜態斷言陳述句來驗證 VS 實作是否支持使用這種型別的方法。但是,當我嘗試添加以下代碼時,出現錯誤C2131: expression did not evaluate to a constant。
union FlagsTypeUnion
{
unsigned flagsAsInt;
FlagsType flags;
constexpr FlagsTypeUnion(unsigned const f = 0) : flagsAsInt{ f } {}
};
static_assert(FlagsTypeUnion{ 1 }.flags.flag0,
"The code currently assumes bit-fields are packed from LSB to MSB");
有沒有辦法添加編譯時檢查來驗證型別雙關和位打包代碼是否像運行時代碼所假設的那樣作業?不幸的是,此代碼分布在整個代碼庫中,因此更改結構實際上并不可行。
uj5u.com熱心網友回復:
您可能會使用std::bit_cast(C 20):
struct FlagsType
{
unsigned flag0 : 1;
unsigned flag1 : 1;
unsigned flag2 : 1;
unsigned padding : 32 - 3; // Needed for gcc
};
static_assert(std::is_trivially_constructible_v<FlagsType>);
constexpr FlagsType makeFlagsType(bool flag0, bool flag1, bool flag2)
{
FlagsType res{};
res.flag0 = flag0;
res.flag1 = flag1;
res.flag2 = flag2;
return res;
}
static_assert(std::bit_cast<unsigned>(makeFlagsType(true, false, false)) == 1);
演示
- clang 不支持它(還)。
- gcc 需要顯式添加填充位以進行
constexpr檢查。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/465308.html
標籤:C 视觉工作室 c 11 视觉工作室 2017 类型双关语
上一篇:為什么這個代碼片段有效?lambda的引數應該是一個左值參考,而`std::bind`傳遞一個右值(即`std::move(ptr)`)給它
