具有位移的表达式中的隐式类型转换

时间:2011-09-15 17:16:40

标签: c++ 64-bit

在下面的代码中,为什么 1字节anUChar会自动转换为4个字节以产生所需的结果0x300(如果anUChar保留1个字节,则代替0x0大小):

unsigned char anUChar = 0xc0; // only the two most significant bits are set
int anInt = anUChar << 2; // 0x300 (correct)

在此代码中,针对64位结果,不会自动转换为8个字节:

unsigned int anUInt = 0xc0000000; // only the two most significant bits are set
long long aLongLong = anUInt << 2; // 0x0 (wrong, means no conversion occurred)

只放置一个显式类型转换:

unsigned int anUInt = 0xc0000000;
long long aLongLong = (long long)anUInt << 2; // 0x300000000 (correct)

最重要的是,这种行为在针对64位计算机的程序中是一样的吗?

顺便说一下,两者中哪一个是最正确且最便携的:(type)var << 1((type)var) << 1

4 个答案:

答案 0 :(得分:2)

算术期间,

char始终会被提升为int。我认为这是C标准中指定的行为。

但是,int不会自动提升为long long

some situations下,如果你试图左移一个较小的整数并将它存储到一个较大的整数中,一些编译器(Visual Studio)实际上会警告你。

  

顺便说一下,两者中哪一个是最正确且最便携的:(type)var << 1((type)var) << 1

两者都很好,便携。虽然我更喜欢第一个,因为它更短。施放的优先级高于移位。

答案 1 :(得分:2)

转化会发生。问题是表达式anUInt << 2unsigned int的结果,因为anUIntunsigned int

anUInt投射到long long(实际上,这是特殊情况下的转换)是正确的做法。

(type)var << 1((type)var) << 1都不正确或可移植,因为标准严格定义了运算符优先级。但是,后者可能更好因为人们更容易理解随便查看代码的人。其他人可能不同意这种说法。

编辑:

请注意,在您的第一个示例中:

unsigned char anUChar = 0xc0; 
int anInt = anUChar << 2; 

...表达式anUChar << 2的结果不是您所期望的unsigned char,而是int,因为积分推广。

operator<<的操作数是整数或枚举类型(参见标准5.8 / 1)。当调用期望算术或枚举类型的操作数的二元运算符时,编译器会尝试将两个操作数转换为相同的类型,以便表达式可以产生公共类型。在这种情况下,对两个操作数(5/9)执行整体提升。当unsigned char参加整体促销活动时,如果您的平台可以在int中容纳unsigned char的所有可能值,则会转换为int,否则它将会被转换为unsigned int转换为{{1}}(4.5 / 1)。

答案 2 :(得分:1)

由于整数促销。对于大多数运营商(例如<<),char个操作数首先会提升为int

这与计算结果的去向无关。换句话说,您的第二个示例分配给long long的事实不会影响操作数的提升。

答案 3 :(得分:1)

对于bitshift操作,较短的整数类型被提升为int类型。这与您指定班次结果的类型无关。

在64位计算机上,你的第二段代码同样有问题,因为int类型通常也是32位宽。 (在x86和x64之间,long long int通常总是64和int 32位,只有long int取决于平台。)

(根据C ++的精神,我会将转换写为(unsigned long long int)(anUInt) << 2,唤起转换构造函数语法。第一组括号纯粹是因为类型名称由几个标记组成。)

我还希望仅在无符号类型上进行位移,因为只有无符号类型可以被认为是等效的(就而言)到它们自己的位模式值。