tl; dr位操作是否安全,并且在整数提升时的预期行为(类型短于int
)?使用整数提升的位操作
例如
uint8_t a, b, c;
a = b & ~c;
这是什么,我有一个粗略的MCVE:
struct X { // this is actually templated
using U = unsigned; // U is actually a dependent name and can change
U value;
};
template <bool B> auto foo(X x1, X x2) -> X
{
if (B)
return {x1.value | x2.value};
else
return {x1.value & ~x2.value};
}
这个伟大的工程,但是当U
变更为整型短于int
,例如std::uint8_t
则由于整型的提升,我得到一个警告:
警告:缩小的“(INT)转换(((无符号 字符)((int)的x1.X ::值))|((无符号字符)((int)的x2.X ::值)))”从 'INT' 为 'X ::∪{又名无符号字符}' 内{} [-Wnarrowing]
所以我添加一个static_cast
:
struct X {
using U = std::uint8_t;
U value;
};
template <bool B> auto foo(X x1, X x2) -> X
{
if (B)
return {static_cast<X::U>(x1.value | x2.value)};
else
return {static_cast<X::U>(x1.value & ~x2.value)};
}
问题:能否整数提升,然后narro翼投与预期结果(*)混乱?特别是因为这些是演员改变签名的前后(unsigned char
- >int
- >unsigned char
)。如果U
已签名,那么怎么办?std::int8_t
(它不会在我的代码中签名,但会对此行为感到好奇)。
我常见的sens说代码完全正常,但是我的C++偏执狂说至少有一个实现定义行为的机会。
(*)是它的不明确的情况下(或I弄乱)的预期行为是设置或清除位(x1
是值,x2
是掩模,B
是设置/清除操作)
(签订目标):这些位操作的情况下,我认为任何结果可以表示回目标类型,从而避免实现定义的行为。我对么? – bolov
在所有*正常*架构中,你是对的。我想知道什么可能会破坏那个('int8_t'是两个补码,但是普通的'int'不是),并且如果这可以按照标准被允许的话。现在我没有明确的答案... –
@bolov:我已经深入了解标准,并且没有任何东西禁止一个实现支持'int8_t'类型,但是使用*符号和幅度*来获得普通的'int'。在这种情况下'((int8_t)-128)| (int8_t)1'可以给'-129'应用积分促销(转换为int)。因此,没有什么能保证按位操作对签名类型是稳定的(导致与操作数类型相同)。 –