用C的数据类型宽度扩展来解释char c=128;printf("%d",c);问题

来源:互联网 发布:服务器地址和端口号 编辑:程序博客网 时间:2024/05/22 00:15

代码编译运行环境:VC++ 2012+Debug+Win32


1.问题描述

在编程或者面试过程中,会遇到如下问题:

char c=128;printf("%d",c); //输出-128

为什么一个正整数128以整型int输出却变成了一个负数?

2.问题分析

在理解上面的问题时,我们需要先了解如下问题。

(1)char型所能表示的数据范围是-128~127。当把128赋值给char型变量时,那么内存中实际存储的是什么呢?
将以上面的代码在Debug模式下转到反汇编,汇编代码如下:

    char c=128;00B16AB0  mov         byte ptr [c],80h      printf("%d",c);00B16AB4  movsx       eax,byte ptr [c]  00B16AB8  mov         esi,esp  00B16ABA  push        eax  00B16ABB  push        0B1EC90h  00B16AC0  call        dword ptr ds:[0B2240Ch]  00B16AC6  add         esp,8  00B16AC9  cmp         esi,esp  00B16ACB  call        __RTC_CheckEsp (0B113CFh)  

从汇编代码可以看出,char型变量c中存储的是128的补码:10000000。注意对于计算机来说,存储的都是数据的补码。反码、源码都对于编程人员理解数据的变换过程提出来的。

(2)当char转换为int时,内存中的数据如何从1个字节扩展到4个字节?
这个是本文的核心问题,理解了这个问题,就可以很好地解释为什么char c=128;printf(“%d”,c); 输出的是-128。

当char型扩展到int型时,C标准中有有如下规则:

一、短数据类型扩展为长数据类型
1、要扩展的短数据类型为有符号数
进行符号扩展,即短数据类型的符号位填充到长数据类型的高字节位(即比短数据类型多出的那一部分),保证扩展后的数值大小不变

例1:char x=10001001b; short y=x; 则y的值应为11111111 10001001b;

例2:char x=00001001b; short y=x; 则y的值应为00000000 00001001b;

2、要扩展的短数据类型为无符号数*

进行零扩展,即用零来填充长数据类型的高字节位

例1:unsigned char x=10001001b; short y=x; 则y的值应为00000000 10001001b;

例2:unsigned char x=00001001b; short y=x; 则y的值应为00000000 00001001b;

二、长数据类型缩减为短数据类型
如果长数据类型的高字节全为1或全为0,则会直接截取低字节赋给短数据类型;如果长数据类型的高字节不全为1或不全为0,则转换就会发生错误。

三、同一长度的数据类型中有符号数与无符号数的相互转化
直接将内存中的数据赋给要转化的类型,数值大小则会发生变化,因为以不同类型解释同一段内存数据会得到不同的数值。比如一个字节中存放的数据是11111111,以unsigned char来解释就是255,以char来解释就是-128.

根据以上规则,可以得出当char c 是一个有符号的字符变量,其内存中存储的是1000 0000,但当它被传送到printf函数的参数时,是将c按照int来进行宽度扩展后再传给printf的。

128的补码是 1000 0000,16进制是0x80, 当它扩展为 int时,由于int是4个字节,需要进行短数据类型扩展到长数据类型。由于内存中存放的是10000000,以char型来解释的话第一位为符号位,表示负数,进行符号扩展为int后,int型变量中存储的数据是:11111111 11111111 11111111 1000000,即0xffffff80。以int来解释的这四个字节的数据,其值就是-128,以unsigned int来解释的话,就是2321127=4294967168

3.代码验证

根据以上分析,我们可以清楚准确的推断出下面的输出。

    unsigned char uc=128;    char c=128;    printf("%d\n",uc);      //128    printf("%d\n",c);       //-128    printf("%u\n",uc);      //128    printf("%u\n",c);       //4294967168    printf("%08x\n",uc);    //0x00000080    printf("%x\n",c);       //0xffffff80

应该不会为这些输出结果而感到惊讶和困惑了吧!有问题欢迎讨论。


参考文献

[1]类型扩展.http://blog.sina.com.cn/s/blog_6adcb3530101cmsd.html
[2]char c=128;.http://blog.csdn.net/jinbi/article/details/6779713

1 0
原创粉丝点击