我们发现了一些奇怪的值,下面是一个小测试用例。 这将打印“FFFFFFFFF9A64C2A”。这意味着无符号的长长似乎已被标记延长。 但为什么 ? 下面的所有类型都是无符号的,那么符号扩展的是什么?预期的产出 将是“F9A64C2A”。
#include <stdio.h>
int main(int argc,char *argv[])
{
unsigned char a[] = {42,76,166,249};
unsigned long long ts;
ts = a[0] | a[1] << 8U | a[2] << 16U | a[3] << 24U;
printf("%llX\n",ts);
return 0;
}
答案 0 :(得分:5)
在表达式a[3] << 24U
中,a[1]
的类型为unsigned char
。现在,“整数提升”会将其转换为int
,因为:
以下内容可用于
int
或unsigned int
的任何地方 使用:[...]
如果
int
可以表示原始类型的所有值,则该值将转换为int
; 否则,它将转换为unsigned int
。
((draft) ISO/IEC 9899:1999,6.3.1.1 2)
请注意,移位运算符(除了大多数其他运算符之外)不执行“通常的算术转换”,将两个操作数转换为通用类型。但是
结果的类型是提升的左操作数的类型。
(6.5.7 3)
在32位平台上,249 << 24 = 4177526784
被解释为int
,其符号位已设置。
只需更改为
ts = a[0] | a[1] << 8 | a[2] << 16 | (unsigned)a[3] << 24;
修复了问题(常量的后缀U
没有影响)。
答案 1 :(得分:1)
ts = ((unsigned long long)a[0]) | ((unsigned long long)a[1] << 8U) | ((unsigned long long)a[2] << 16U) | ((unsigned long long)a[3] << 24U);
强制转换可防止将中间结果转换为默认的int类型。
答案 2 :(得分:1)
当自[{1}}自动转换为unsigned char
时,某些移位a [i]会产生符号扩展值。
这符合6.3.1算术操作数,6.3.1.1小节标准N1570的布尔,字符和整数,其部分内容为“2.以下内容可用于任何地方可以使用int或unsigned int:... - 具有整数类型的对象或表达式(int或unsigned int除外) 其整数转换等级小于或等于int和unsigned int的等级。 ...如果int可以表示原始类型的所有值...,则该值将转换为int;否则,它将转换为unsigned int。这些被称为整数促销。 ... 3.整数促销保留包括符号的值。“
参见例如www.open-std.org/JTC1/SC22/WG14/www/docs/n1570.pdf
您可以使用以下代码,它可以正常运行:
int