2012-07-22 94 views
0
#include <stdio.h> 
#include <stdlib.h> 

int main(int argc, char **argv){ 
    char i = -128; 
    int j = i; 
    printf("%d %u\n", j, j); 
    return 0; 
} 

结果是-128 4294967168怎样的printf知道符号扩展后打印出什么

什么,我认为是

i: 10000000 

和赋值运算符后,执行符号扩展

j: 11111111 11111111 11111111 10000000 

我想问的是如何printf("%d",j)知道要打印-128绝对t使用

最后一个字节?怎么运行的?

Thx!

+0

你真的会打印'-127'吗? – 2012-07-22 19:32:10

+0

@ Jonathan Leffler是的,我真的明白了。 – 2012-07-22 19:33:29

+0

非常有趣;你在运行什么硬件?当我使用'-fsigned-char'在Mac OS X 10.7.4上进行编译时,我得到了'-128 4294967168'(这两者与你报告的内容相差1);当我用'-funsigned-char'编译时,我得到'128 128'。分配给int时,我没有看到编译器将分配给'char'的-128'转换为'-127'的合法方式。 – 2012-07-22 19:41:35

回答

6

我想问的是printf(“%d”,j)知道如何打印-128只是使用最后一个字节?

它没有。它被告知打印一个签名的int,所以它从堆栈中获取适当数量的字节(通常为4),并将该位模式解释为签名为int

当您将负charint变量,如int j = i;这里发生的事情是不是真的符号扩展,但 - 因为所有值的char可以代表也可表示为int - 一个保值转换,chari被转换为具有相同值的int。在现在最普遍的补码机器上,也是在补码中,保值转换恰好与符号扩展一致,但是如果代表是符号和幅度,转换会有所不同。

由于-128不能表示为1的补码或符号和幅度中的带符号八位整数,我们来看看将-127转换为32位带符号整数时发生的位模式变化同一种表示方法:

两个补:

10000001 -> 11111111 11111111 11111111 10000001 

的补:

10000000 -> 11111111 11111111 11111111 10000000 

登录和幅度:

11111111 -> 10000000 00000000 00000000 01111111 
+1

'j'已经是'int'了,不是吗? – 2012-07-22 19:33:30

+0

哦,对。被“只使用最后一个字节?”所迷惑。 – 2012-07-22 19:36:47

+0

@ Liang-YuPan假设标准二进制补码和八位(带符号)char,32位int,char i = -128;的位模式是10000000或十六进制0x80, 'int'-128的位模式,不管它是通过从char转换还是以其他方式获得,都在上面的假设'0xFFFFFF80'(为了简洁起见,十六进制)之下。所以当'printf'打印一个有符号整数('%d')并找到该位模式时,它会打印-128。当它将该位模式解释为无符号整数('%u')时,该值为'2^32 - 128 = 4294967168'。 – 2012-07-22 20:08:19

2

它只是打印未签名的版本-128(在这种情况下为int)。

1

您强制投看到一个整数的第一个字节:

char j = -128; 
printf("%d", (char) j); 

看到第二个字节为十进制,你强制投之一:

printf("%d", *(((char *) &j) + 1)); 

的最后一个字节一个整数:

printf("%d", *(((char *) &j) + 3)); 
1

您的程序正在调用未定义的行为通过将错误的类型传递给printf%u需要unsigned参数,但您通过了(签名)intprintf不“知道该做什么”,因为它不需要特别做任何事情;你可以自由地做任何事情,因为你调用了UB。

1

这是一个简单的测试程序,可以帮助您了解正在发生的事情。需要注意的是它使用C99长度修改hh,这意味着:

hh用于指定后续dioux,或X转换说明适用于 signed charunsigned char参数(该参数将有 根据整数升级推广,但其打印前的价值应为 转换为signed charunsigned char);或者 后面的n转换说明符适用于指向signed char 参数的指针。

这可能会帮助您了解类型的处理方式。

#include <stdio.h> 
#include <limits.h> 

static void print_value(signed char sc, unsigned char uc, /*plain*/ char pc) 
{ 
    int j1 = sc; 
    int j2 = uc; 
    int j3 = pc; 
    printf("%-9s %4hhd %4hhu %4d 0x%hhX %10u\n", "Signed:", j1, j1, j1, j1, j1); 
    printf("%-9s %4hhd %4hhu %4d 0x%hhX %10u\n", "Unsigned:", j2, j2, j2, j2, j2); 
    printf("%-9s %4hhd %4hhu %4d 0x%hhX %10u\n", "Plain:", j3, j3, j3, j3, j3); 
} 

static void check_value(int i) 
{ 
     signed char sc = i; 
     unsigned char uc = i; 
     /*plain*/ char pc = i; 
     print_value(sc, uc, pc); 
} 

int main(void) 
{ 
    for (int i = 0; i <= 3; i++) 
     check_value(i); 
    for (int i = SCHAR_MAX - 3; i <= SCHAR_MAX+3; i++) 
     check_value(i); 
    for (int i = UCHAR_MAX - 3; i <= UCHAR_MAX; i++) 
     check_value(i); 
    return 0; 
} 

-fsigned-char编译(所以 '纯' char是签名型),输出是:

Signed:  0 0 0 0x0   0 
Unsigned:  0 0 0 0x0   0 
Plain:  0 0 0 0x0   0 
Signed:  1 1 1 0x1   1 
Unsigned:  1 1 1 0x1   1 
Plain:  1 1 1 0x1   1 
Signed:  2 2 2 0x2   2 
Unsigned:  2 2 2 0x2   2 
Plain:  2 2 2 0x2   2 
Signed:  3 3 3 0x3   3 
Unsigned:  3 3 3 0x3   3 
Plain:  3 3 3 0x3   3 
Signed:  124 124 124 0x7C  124 
Unsigned: 124 124 124 0x7C  124 
Plain:  124 124 124 0x7C  124 
Signed:  125 125 125 0x7D  125 
Unsigned: 125 125 125 0x7D  125 
Plain:  125 125 125 0x7D  125 
Signed:  126 126 126 0x7E  126 
Unsigned: 126 126 126 0x7E  126 
Plain:  126 126 126 0x7E  126 
Signed:  127 127 127 0x7F  127 
Unsigned: 127 127 127 0x7F  127 
Plain:  127 127 127 0x7F  127 
Signed: -128 128 -128 0x80 4294967168 
Unsigned: -128 128 128 0x80  128 
Plain:  -128 128 -128 0x80 4294967168 
Signed: -127 129 -127 0x81 4294967169 
Unsigned: -127 129 129 0x81  129 
Plain:  -127 129 -127 0x81 4294967169 
Signed: -126 130 -126 0x82 4294967170 
Unsigned: -126 130 130 0x82  130 
Plain:  -126 130 -126 0x82 4294967170 
Signed:  -4 252 -4 0xFC 4294967292 
Unsigned: -4 252 252 0xFC  252 
Plain:  -4 252 -4 0xFC 4294967292 
Signed:  -3 253 -3 0xFD 4294967293 
Unsigned: -3 253 253 0xFD  253 
Plain:  -3 253 -3 0xFD 4294967293 
Signed:  -2 254 -2 0xFE 4294967294 
Unsigned: -2 254 254 0xFE  254 
Plain:  -2 254 -2 0xFE 4294967294 
Signed:  -1 255 -1 0xFF 4294967295 
Unsigned: -1 255 255 0xFF  255 
Plain:  -1 255 -1 0xFF 4294967295 

与-funsigned炭编译(so 'plain' char`是一个无符号类型),输出是:

Signed:  0 0 0 0x0   0 
Unsigned:  0 0 0 0x0   0 
Plain:  0 0 0 0x0   0 
Signed:  1 1 1 0x1   1 
Unsigned:  1 1 1 0x1   1 
Plain:  1 1 1 0x1   1 
Signed:  2 2 2 0x2   2 
Unsigned:  2 2 2 0x2   2 
Plain:  2 2 2 0x2   2 
Signed:  3 3 3 0x3   3 
Unsigned:  3 3 3 0x3   3 
Plain:  3 3 3 0x3   3 
Signed:  124 124 124 0x7C  124 
Unsigned: 124 124 124 0x7C  124 
Plain:  124 124 124 0x7C  124 
Signed:  125 125 125 0x7D  125 
Unsigned: 125 125 125 0x7D  125 
Plain:  125 125 125 0x7D  125 
Signed:  126 126 126 0x7E  126 
Unsigned: 126 126 126 0x7E  126 
Plain:  126 126 126 0x7E  126 
Signed:  127 127 127 0x7F  127 
Unsigned: 127 127 127 0x7F  127 
Plain:  127 127 127 0x7F  127 
Signed: -128 128 -128 0x80 4294967168 
Unsigned: -128 128 128 0x80  128 
Plain:  -128 128 128 0x80  128 
Signed: -127 129 -127 0x81 4294967169 
Unsigned: -127 129 129 0x81  129 
Plain:  -127 129 129 0x81  129 
Signed: -126 130 -126 0x82 4294967170 
Unsigned: -126 130 130 0x82  130 
Plain:  -126 130 130 0x82  130 
Signed:  -4 252 -4 0xFC 4294967292 
Unsigned: -4 252 252 0xFC  252 
Plain:  -4 252 252 0xFC  252 
Signed:  -3 253 -3 0xFD 4294967293 
Unsigned: -3 253 253 0xFD  253 
Plain:  -3 253 253 0xFD  253 
Signed:  -2 254 -2 0xFE 4294967294 
Unsigned: -2 254 254 0xFE  254 
Plain:  -2 254 254 0xFE  254 
Signed:  -1 255 -1 0xFF 4294967295 
Unsigned: -1 255 255 0xFF  255 
Plain:  -1 255 255 0xFF  255 

在Mac OS X 10.7.4上使用GCC 4.7.1编译(但在平台上使用标准C库)。