前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >用C的数据类型宽度扩展来解释char c=128;printf("%d",c);问题

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

作者头像
恋喵大鲤鱼
发布2018-08-03 16:41:04
9320
发布2018-08-03 16:41:04
举报
文章被收录于专栏:C/C++基础C/C++基础

代码编译运行环境:Windows 64bits+VS2017+Debug+Win32


1.问题描述

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

代码语言:javascript
复制
char c=128;
printf("%d",c); //输出-128

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

2.问题分析

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

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

代码语言:javascript
复制
    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的补码:10000000b。注意对于计算机来说,整型数值存储的都是补码,而反码、源码是为了方便编程人员理解数据的变换而提出来的。

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

当char型扩展到int型时,C标准中有如下规则: (2.1)短数据类型扩展为长数据类型 (a)要扩展的短数据类型为有符号数,进行符号扩展,即短数据类型的符号位填充到长数据类型的高字节位(即比短数据类型多出的那一部分),保证扩展后的数值大小不变

代码语言:javascript
复制
char x=10001001b;   short y=x;  则y的值应为11111111 10001001b;   //例1
char x=00001001b;   short y=x;  则y的值应为00000000 00001001b;   //例2

(b)要扩展的短数据类型为无符号数,进行零扩展,即用零来填充长数据类型的高字节位。

代码语言:javascript
复制
unsigned char x=10001001b;   short y=x;  则y的值应为00000000 10001001b;  //例1
unsigned char x=00001001b;   short y=x;  则y的值应为00000000 00001001b;  //例2

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

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

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

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

3.代码验证

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

代码语言:javascript
复制
    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]类型扩展 [2]char c=128

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2015年11月27日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.问题描述
  • 2.问题分析
  • 3.代码验证
  • 参考文献
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档