按位运算符和整数提升会发生什么?

Wan*_*ool 11 c++ bitwise-operators integer-promotion unsigned-integer signed-integer

我有一个简单的程序.请注意,我使用的是无符号的固定宽度整数1字节.

#include <cstdint>
#include <iostream>
#include <limits>

int main()
{
    uint8_t x = 12;
    std::cout << (x << 1) << '\n';
    std::cout << ~x;

    std::cin.clear();
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    std::cin.get();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我的输出如下.

24
-13
Run Code Online (Sandbox Code Playgroud)

我测试了更大的数字,操作员<<总是给我正数,而操作员~总是给我负数.我然后使用sizeof()并发现......

当我使用左移位运算符(<<)时,我收到一个无符号的4字节整数.

当我使用bitwise not运算符(~)时,我收到一个带符号的4字节整数.

似乎bitwise not运算符(~)像算术运算符一样执行有符号整数提升.但是,左移运算符(<<)似乎提升为无符号整数.

我觉得有必要知道编译器什么时候改变我背后的东西.如果我在分析中是正确的,那么所有按位运算符都会提升为4字节整数吗?为什么一些签名和一些未签名?我很困惑!

编辑:我总是得到肯定或总是得到负值的假设是错误的.但是由于错误,我理解真正发生的事情,这要归功于下面的重要答案.

use*_*267 8

[expr.unary.op]

操作数~应具有整数或无范围的枚举类型; 结果是其操作数的一个补码.执行整体促销.

[expr.shift]

转移运营商<<>>组从左到右.[...]操作数应为整数或无范围的枚举类型,并执行整体促销.

什么是整体推广uint8_t(通常会unsigned_char在幕后)?

[conv.prom]

以外的整数类型的prvalue bool,char16_t,char32_t,或 wchar_t,其整数转换秩(4.13)小于的秩 int可以被转换成类型的prvalue int如果int可以表示源类型的所有值; 否则,源prvalue可以转换为类型的prvalue unsigned int.

所以int,因为a的所有值uint8_t都可以表示int.

什么是int(12) << 1int(24).

什么是~int(12)int(-13).

  • 因为它们都是 1 个字节,所以我希望 AND 运算的结果也是 1 个字节!那么“uint64_t”呢?由于它比“int”大,因此 2 个“uint64_t”的 AND 运算的结果是“uint64_t”。这表明该语言存在缺陷,根本不一致。 (2认同)

650*_*502 5

出于性能原因,C和C++语言被认为int是"最自然的"整数类型,而"类型"的类型比int被认为是"存储"类型的类型更小.

在表达式中使用存储类型时,它会自动转换为a intunsigned int隐式.例如:

// Assume a char is 8 bit
unsigned char x = 255;
unsigned char one = 1;

int y = x + one; // result will be 256 (too large for a byte!)
++x;             // x is now 0
Run Code Online (Sandbox Code Playgroud)

发生了什么,x并且one在第一个表达式中已经隐式转换为整数,已经计算了加法并且结果已经存储回整数.换句话说,未使用两个无符号字符执行计算.

同样,如果float表达式中有值,编译器将要做的第一件事就是将其提升为a double(换句话说,它float是一种存储类型,double而不是浮点数的自然大小).这是其中的原因,如果你使用printf打印彩车你不需要说%lf的int格式字符串和%f足够的(%lf是需要scanf但因为该函数存储结果float可能比一个更小double).

C++使问题变得复杂很多,因为在将参数传递给函数时,您可以区分ints和较小的类型.因此,在每个表达式中执行转换并不总是如此...例如,您可以:

void foo(unsigned char x);
void foo(int x);
Run Code Online (Sandbox Code Playgroud)

哪里

unsigned char x = 255, one = 1;
foo(x);       // Calls foo(unsigned char), no promotion
foo(x + one); // Calls foo(int), promotion of both x and one to int
Run Code Online (Sandbox Code Playgroud)