我很惊讶C ++在按位时不应用于无符号字符时的行为。
获取二进制值01010101b
,即0x55
或85
。不按位比特应用8位表示应该产生10101010b
,即0xAA
或170
。
但是,我无法在C ++中重现上述内容。以下简单断言失败。
assert(static_cast<unsigned char>(0xAAu) == ~static_cast<unsigned char>(0x55u));
我使用以下代码打印了0x55
,0xAA
和~0x55
(作为uchar)的值。并且它揭示了按位并不能达到我的预期。
std::cout << "--> 0x55: " << 0x55u << ", 0xAA: " << 0xAAu << ", ~0x55: "
<< static_cast<unsigned>(~static_cast<unsigned char>(0x55u)) << std::endl;
--> 0x55: 85, 0xAA: 170, ~0x55: 4294967210
为~0x55
打印的数字等于11111111111111111111111110101010b
,这是32位按位而不是0x55
。因此,即使我明确地将输入转换为~
,unsigned char
运算符也在32位整数上运行。那是为什么?
我应用了另一个测试来查看~
运算符返回的类型。在int
输入上结果为unsigned char
:
template <class T>
struct Print;
// inside main()
Print<decltype(~static_cast<unsigned char>(0x55))> dummy;
产生以下编译器错误,表明结果类型为int
。
error: implicit instantiation of undefined template 'Print<int>'
Print<decltype(~static_cast<unsigned char>(0x55u))> dummy;
我做错了什么?或者,如何让C ++从0xAA
生成~0x55
?
完整代码为here
答案 0 :(得分:9)
在~
的操作数上执行整体促销活动我们可以通过转到draft C++ standard部分5.3.1
一元运算符来查看(强调我的):
〜的操作数应具有整数或无范围的枚举类型;该 结果是其操作数的补码。 整体促销 执行。结果的类型是提升的操作数的类型[...]
并在4.5
整体促销部分介绍了整体促销活动,并说:
除bool,char16_t,char32_t或之外的整数类型的prvalue wchar_t,其整数转换等级(4.13)小于等级 如果int可以表示all,则int可以转换为int类型的prvalue 源类型的值;
为了完整性,要看到 unsigned char 等级小于 int 的等级,我们可以转到4.13
部分转换等级< / em>其中说:
有符号整数类型的等级应大于等级 任何带有较小尺寸的有符号整数类型。
和
char的等级应等于signed char和unsigned的等级 炭。
一种解决方案是将结果分配给 unsigned char ,这是安全的,因为您不必担心有符号整数溢出。
正如Ben Voigt所指出的,它将符合sizeof (int) == 1
和CHAR_BIT >= 32
的系统。在这种情况下,unsigned char的等级woudl不小于int,因此促销将是unsigned int。我们不知道实际发生的任何系统。
答案 1 :(得分:2)
关于积分推广的答案是正确的。
您可以通过按正确的顺序进行投射和注释来获得所需的结果:
assert(static_cast<unsigned char>(0xAAu) == static_cast<unsigned char>(~0x55u));
答案 2 :(得分:1)
您可以通过将~0x55
的结果分配给unsigned char
来“截断”前导1:
#include <iostream>
int main()
{
unsigned char input = 0x55;
unsigned char output = ~input;
std::cout << "input: " << (int)input << " output: " << (int)output << std::endl;
return 0;
}
结果:
input: 85 output: 170