在C中的printf()中将int类型化为char

dis*_*ree 2 c casting

int *int_pointer = malloc(10);

*int_pointer = 53200;

printf("The integer at byte #0 is set to: %d \n", (char) *int_pointer);
Run Code Online (Sandbox Code Playgroud)

结果:-48

所以我只是试着看看会发生什么,我得到了这个意想不到的结果.

为什么-48?它甚至变成了负面的?

Grz*_*ski 8

语言 - 律师观点:

我相信C99/C11标准中的正确参考是§6.3.1.3(强调我的):

  1. 当具有整数类型的值转换为除_Bool之外的另一个整数类型时,如果该值可以由新类型表示,则它将保持不变.
  2. 否则,如果新类型是无符号的,则通过重复地添加或减去一个可以在新类型中表示的最大值来转换该值,直到该值在新类型的范围内.
  3. 否则,新类型将被签名,并且值无法在其中表示 ; 结果是实现定义的,或者引发实现定义的信号.

请注意,char类型是有问题的,因为如果它实际上表示为有符号或无符号,它也是实现定义的.标准本身完全定义的唯一方法是转换为unsigned char类型.

实践观点:

假设对于您的实现sizeof(int) == 4并且它使用二进制补码方法来存储有符号整数,则该数字53200表示为:

0000 0000 0000 0000 1100 1111 1101 0000
Run Code Online (Sandbox Code Playgroud)

请注意,如果你有小端CPU(可能是它的真实假设),那么字节顺序,或者更严格的是它们实际存储在内存和CPU寄存器中的方式是反转的,即该数字存储为:

0000 1101 1111 1100 0000 0000 0000 0000
Run Code Online (Sandbox Code Playgroud)

什么(unsigned char) 53200产生的是(在纯数学意义上的)减法的(注意,标准保证的结果sizeof(unsigned char) == 1):

53200 - 256 - 256 - ... - 256 = 53200 % 256 = 208
Run Code Online (Sandbox Code Playgroud)

这是二进制的 1101 0000

可以在数学上证明结果总是与"截止"相同,仅作为演员的结果仅保留最后,最不重要的字节.

注意printf():

正如指出的@pmg printf()是可变参数函数,并且由于默认参数推广其类型的可选参数unsigned char(或signed char和char作为阱)一直晋升到int,但这次是"只是一种形式".

注意替代双向运算符解决方案:

作为替代解决方案,您可以使用biwise & 和 operator使用适当的掩码来获取特定数字的最低有效字节,例如:

*int_number & 0xff   /* mask is 0000 0000 0000 0000 1111 1111 */
Run Code Online (Sandbox Code Playgroud)


Kil*_*oth 5

将数据类型转换为另一种不足以容纳所有可能值的数据类型是未定义的行为.对于未定义的行为,编译器可以随心所欲地执行任何操作,因此通常它会为实现者执行最少的工作,因为它们是自动正确的并且您总是错误的.

因此,你不要问"为什么会这样?" - 你应该很高兴你没有得到52301,或42,或"帮助!我被困在整数库中!" 代替.