在C中使用铸造的奇怪现象

时间:2014-06-18 07:59:14

标签: c

以下代码:

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

这似乎非常奇怪。任何人都知道为什么会这样发生?

2 个答案:

答案 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;

十六进制常量的类型是以下类型中的第一个,其值可以表示为:intunsigned intlong intunsigned 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 intunsigned int不是兼容类型,因此代码的行为未定义。通常,signed int的位被重新解释为signed int,这会产生十六进制常量的原始值。

调用可变参数函数

unsigned int

printf(...);是一个可变函数。变量函数(通常)使用与普通函数不同的调用约定。如果您在范围内没有printf()的有效声明,则您的代码会调用未定义的行为

print()提供声明的常用方法是printf()


资料来源:n1570(当前C标准的最后公开草案)。