为什么打印255

时间:2015-01-07 05:56:16

标签: c type-conversion

int main()
{

     unsigned char a = -1;
     printf("%d",a);
     printf("%u",a);
}

当我执行上述程序时,我得到255 255作为答案。

我们知道负数将存储在2的补码中。

因为它是2的补码,所以表示将是 1111 1111 - > 2'补充。

但在上面我们打印%d(int)但整数是四个字节。

我的假设是即使它是字符我们正在强制编译器将其视为整数。 所以它在内部使用符号扩展概念。

1111 1111 1111 1111 1111 1111 1111 1111

根据上面的表示,在第一种情况下它必须是-1,因为它是%d(有符号)。 在第二种情况下,它必须打印(2 ^ 31-1),但它打印255和255。 为什么在两种情况下都打印255。 告诉我,如果我的假设是错误的,并给我真正的解释。

5 个答案:

答案 0 :(得分:2)

你的假设是错误的;这个角色将会翻身#34;到255,然后填充到整数的大小。假设一个32位整数:

11111111

将填充到:

00000000 00000000 00000000 11111111

答案 1 :(得分:0)

unsigned char0-255开始,因此负数-1将打印255 -2将打印254等等...... < / p>

signed char-128 to +127开始运行,因此对于同一printf(),您获得-1,而unsigned char

则不然

在对char进行赋值后,其余的整数值将被填充,因此您对2^31的假设是错误的。

负数用2的补码表示(取决于实现)

所以

1 = 0000 0001

所以为了得到-1我们做

----------------------------------------
2's complement      = 1111 1111 = (255) |
-----------------------------------------

答案 2 :(得分:0)

编译器不知道printf 中的额外参数应该是什么类型,因为唯一指定它的东西应该被视为4字节{{1格式字符串,在编译时无关紧要。

幕后实际发生的是被调用者(int)接收到每个参数的指针,然后转换为适当的类型。

与此大致相同的结果:

printf

由于你可能在一个小端CPU上运行,4字节char a = -1; int * p = (int*)&a; // BAD CAST int numberToPrint = *p; // Accesses 3 extra bytes from somewhere on the stack 0x12345678在内存中安排为int

如果| 0x78 | 0x56 | 0x34 | 0x12 |之后的堆栈上的3个字节都是a(它们可能是由于堆栈对齐,但它不是保证),内存看起来像这样:

0x00

评估为&a: | 0xFF | (int*)&a: | 0xFF | 0x00 | 0x00 | 0x00 |

答案 3 :(得分:0)

直到a的表示,你是对的。但是,%d函数的%uprintf()次转换都以int为参数。也就是说,您的代码与您编写的代码相同

int main() {
     unsigned char a = -1;
     printf("%d", (int)a);
     printf("%u", (int)a);
}

当您将-1分配给a时,您丢失了曾经是有符号值的信息,a的逻辑值为255。现在,当您将unsigned char转换为int时,编译器会保留a的逻辑值,代码将打印255

答案 4 :(得分:0)

打印255,只是因为这是ISO / IEC9899的目的

  

H.2.2整数类型

     

1带符号的C整数类型为int,long int,long long int,以及相应的   无符号类型与LIA-1兼容。如果实现添加了对。的支持   LIA-1例外值''integer_overflow''和''undefined'',然后是那些类型   LIA-1符合类型。在LIA-1意义上,C的无符号整数类型是“模数”   在溢出或越界结果静默包装。定义的实现   有符号整数类型也是模数,不需要检测整数溢出,在这种情况下,   只需要检测整数除零。

如果给出了这一点,那么印刷255绝对是LIA-1所期望的。

否则,如果您的实现不支持C99的LIA-1附件部分,那么它只是未定义的行为。