以下代码:
int main() {
int small_num = 0x12345678;
int largest_num = 0xFFFFFFFF;
printf("small: without casting to short: 0x%.8x, with casting to short: 0x%.8x\n", small_num>>16, (short)(small_num>>16));
printf("large: without casting to short: 0x%.8x, with casting to short: 0x%.8x\n", largest_num>>16, (short)(largest_num>>16));
return 0;
}
给我输出(使用codepad):
small: without casting to short: 0x00001234, with casting to short: 0x00001234
large: without casting to short: 0xffffffff, with casting to short: 0xffffffff
这似乎非常奇怪。任何人都知道为什么会这样发生?
答案 0 :(得分:2)
当你在printf调用中转换为(short)时,编译器会将它从short转换为int,这是传递给printf的参数。因此,1234将映射到1234,并且ffff(正好为-1)映射到ffffffff。注意,通过在位"上添加"将负整数从短到长扩展。在他们的左边。
答案 1 :(得分:0)
十六进制常量的类型为unsigned int
。转换为signed int
后,该值将变为-1
。右移负值通常使符号位保持不变,因此-1 >> 16
仍为-1
。传递给可变参数函数的short int
会被提升为signed int
,当unsigned int
转化说明符解释为%x
时,会打印出0xffffffff
。
但是,您的代码因各种原因而中断。
int largest_num = 0xFFFFFFFF;
十六进制常量的类型是以下类型中的第一个,其值可以表示为:int
,unsigned int
,long int
,unsigned long int
,{{ 1}},long long int
。
如果unsigned long long int
超过32位,那你就没事了。
如果int
的位数为32位或更少,则结果为实现定义(或者实现定义的信号)。
通常,int
将设置所有位并具有值largest_num
。
-1
如果largest_num>>16
的值为负数,则结果值为实现定义。通常,符号位保持不变,因此largest_num
右移仍为-1
。
-1
将printf ("0x%.8x\n", (short)(largest_num>>16));
传递给可变参数函数时,该值将提升为short int
。转换为新类型时,将保留负值。
但是,int
转换说明符需要"%x"
参数。由于unsigned int
和unsigned int
不是兼容类型,因此代码的行为为未定义。通常,signed int
的位被重新解释为signed int
,这会产生十六进制常量的原始值。
unsigned int
printf(...);
是一个可变函数。变量函数(通常)使用与普通函数不同的调用约定。如果您在范围内没有printf()
的有效声明,则您的代码会调用未定义的行为。
为print()
提供声明的常用方法是printf()
。
资料来源:n1570(当前C标准的最后公开草案)。