在下面的代码中,为什么 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
?
答案 0 :(得分:2)
char
始终会被提升为int
。我认为这是C标准中指定的行为。
但是,int
不会自动提升为long long
。
在some situations下,如果你试图左移一个较小的整数并将它存储到一个较大的整数中,一些编译器(Visual Studio)实际上会警告你。
顺便说一下,两者中哪一个是最正确且最便携的:
(type)var << 1
或((type)var) << 1
?
两者都很好,便携。虽然我更喜欢第一个,因为它更短。施放的优先级高于移位。
答案 1 :(得分:2)
转化会发生。问题是表达式anUInt << 2
是unsigned int
的结果,因为anUInt
是unsigned 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
,唤起转换构造函数语法。第一组括号纯粹是因为类型名称由几个标记组成。)
我还希望仅在无符号类型上进行位移,因为只有无符号类型可以被认为是等效的(就值而言)到它们自己的位模式值。