7

当按位而不是无符号字符应用时,我对 C++ 的行为感到惊讶。

取二进制值01010101b,即0x5585。不按位应用八位表示应该产生10101010b,即0xAA,或170

但是,我无法在 C++ 中重现上述内容。以下简单断言失败。

assert(static_cast<unsigned char>(0xAAu) == ~static_cast<unsigned char>(0x55u));

我用下面的代码打印了0x550xAA~0x55(as 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. 这是为什么?

我应用了另一个测试来查看~运算符返回的类型。结果是intunsigned 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;

我究竟做错了什么?0xAA或者,我如何让 C++ 生成~0x55

完整代码在这里

4

3 回答 3

9

积分提升是在操作数上执行的,~我们可以通过C++ 标准草案5.3.1 元运算符看到这一点,它说(强调我的):

〜的操作数应具有整数或无范围枚举类型;结果是其操作数的反码。进行整体促销。结果的类型是提升的操作数的类型 [...]

积分促销包含在4.5 积分促销部分中,并说:

如果 int 可以表示源类型的所有值,则整数转换等级 (4.13) 小于 int 等级的除 bool、char16_t、char32_t 或 wchar_t 的整数类型的纯右值可以转换为 int 类型的纯右值;

为了完整起见,要查看unsigned char等级小于int等级,我们可以转到4.13 Integer conversion rank部分,它说:

有符号整数类型的等级应大于任何尺寸较小的有符号整数类型的等级。

和:

char 的秩应等于signed char 和unsigned char 的秩。

一种解决方案是将结果分配给unsigned char,这是安全的,因为您不必担心有符号整数溢出。

正如 Ben Voigt 指出的那样,拥有一个系统 wheresizeof (int) == 1CHAR_BIT >= 32. 在这种情况下,unsigned char 的等级不会小于 int,因此提升将是 unsigned int。我们不知道这实际上发生在任何系统上。

于 2014-09-29T13:41:35.157 回答
3

关于积分提升的答案是正确的。

您可以通过以正确的顺序强制转换和 NOTting 来获得所需的结果:

assert(static_cast<unsigned char>(0xAAu) == static_cast<unsigned char>(~0x55u));
于 2014-10-01T03:33:08.243 回答
1

~0x55您可以通过将结果分配给 a来“截断”前导 1 unsigned char

#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
于 2014-09-29T13:52:22.263 回答