C 字符到整数转换输出背后的原因是什么?

C 字符到整数转换输出背后的原因是什么?,c,C,例如: int x = 65535; char y = x; printf("%d\n", y) 这将输出-1。是否要手动导出此值?65535是0xffff 转换为字符时,左位将被保留: 0xffff和0xff是0xff 将字符传递给函数时,它将扩展为int。由于字符最左边的位是1,因此它将被符号扩展,因此它将成为0xFFFFFF 32位 这是-1,所以-1打印为。 正如Dasblinkenlight所指出的,字符是有符号的还是无符号的,无论是作为实现中的默认值还是作为声明unsigned c

例如:

int x = 65535; char y = x; printf("%d\n", y)
这将输出-1。是否要手动导出此值?

65535是0xffff

转换为字符时,左位将被保留:

0xffff和0xff是0xff

将字符传递给函数时,它将扩展为int。由于字符最左边的位是1,因此它将被符号扩展,因此它将成为0xFFFFFF 32位

这是-1,所以-1打印为。 正如Dasblinkenlight所指出的,字符是有符号的还是无符号的,无论是作为实现中的默认值还是作为声明unsigned char y,都很重要。我的最后一行将读取未签名字符:

向函数传递未设计的字符时,会将其扩展为无符号整数。由于它是无符号的,所以只在左侧添加零,因此它将变为0x000000ff 32位


这是255,因此255被打印为。

为了手动导出,您需要了解系统的几个实现定义方面,即

如果char已签名或未签名 如果字符已签名,则使用什么表示方案 系统如何处理不能在窄类型中准确表示的值的窄化转换。 尽管该标准允许实现决定,但缩小转换的一种非常常见的方法是截断不适合窄类型的位。假设这是您的系统采用的方法,计算输出的第一部分是查找要转换的int值的最后八位。在您的例子中,65535是11111111112,所以最后八位都是1

现在您需要决定11111112的解释。在您的系统上,字符是有符号的,并且系统使用负数的2的补码表示,因此此模式被解释为8位-1值

调用printf时,有符号字符的8位值将提升为int,因此将打印保留的值

在默认情况下字符无符号的系统上,相同的模式将被解释为255。

65535当转换为二进制时为1111。 当你把它分配给一个字符变量时,它会被修剪为最低有效的8位,即11111

这相当于二进制中的-1。2的任何数字的补码给出其负值,因此2的补码为00000001: 11111110+1=11111111为-1

int x = 65535;
“x”65535的值相当于表示2字节16位数字的十六进制0xffff binary=1111111111111111111

然后,将“x”的值转换为字符“y”,字符数据类型的大小为1字节8位。因此,在分配给“y”时,x的右侧值被截断,因为它只有1B内存空间

所以“y”的值是0xff binary=1111111,在有符号数整数表示中等于-1


我们用整数“%d”来显示“y”字符值。

@MartinJames不太确定,varargs调用的字符会自动升级为int,所以我认为这很好。@unwind-oh-你可能是对的。那么,这是另一组无数次的欺骗:。@MartinJames,这是正确的。该值被正式指定为提升为int,这是%d所需的。我错了,抱歉:行为不是完全未定义的。代码很糟糕,因为它的输出取决于char作为signed/unsigned的实现。@Downvoter,如果您有时间,您能解释一下答案中的不足之处吗?我没有看到任何,我没有投票,但是在C标准中,int到char的转换并没有用位来表示。如果该值可以用新类型表示,则为结果。否则,结果将定义实现,包括陷阱发生的时间。因此,答案至少应该说明,许多实现只是简单地接受低位,并允许它们以其用于char的任何格式重新解释。但是一个实现可能会饱和,例如。@EricPostphil非常感谢您的深思熟虑的评论。我编辑以提及您关于实现定义的缩小转换的观点。如果函数没有原型或它们对应于。。。在函数声明中。这些适用于这种情况,但不适用于一般情况。否则,参数将转换为其相应参数的类型。当将int值转换为char且该值不可表示时,结果由实现定义。许多实现只是按照您的状态取低位,但它们也可能会捕获、饱和或定义其他结果。