char c=128;printf("%d",c);问题

一、文章来由

同属计算机储存,补码问题的延生~~

二、解密

答案输出是-128,为什么呢?

char型变量c中存储的是128的补码:10000000。上一篇文章已经说到,对于计算机来说,存储的都是数据的补码。

赋值给char型,debug模式下反汇编如下:

char c = 128;
00C6446E  mov         byte ptr [c],80h  

    char cc = c;
00C64472  mov         al,byte ptr [c]
00C64475  mov         byte ptr [cc],al
    unsigned int ui = c;
00C64478  movsx       eax,byte ptr [c]
00C6447C  mov         dword ptr [ui],eax
    int i = c;
00C6447F  movsx       eax,byte ptr [c]
00C64483  mov         dword ptr [i],eax
    double d = c;
00C64486  movsx       eax,byte ptr [c]
00C6448A  cvtsi2sd    xmm0,eax
00C6448E  movsd       mmword ptr [d],xmm0
00C64478  movsx       eax,byte ptr [c]

使eax寄存器扩展成为 0xFFFFFF80,扩展在这一步~~

而且

00C64475  mov         byte ptr [cc],al   //char cc = c;
00C6447C  mov         dword ptr [ui],eax //unsigned int ui = c;
00C64483  mov         dword ptr [i],eax  //int i = c;
00C6448E  movsd       mmword ptr [d],xmm0 //double d = c;

进一步将寄存器存到内存中

对于计算机来说

char c = -128;
signed char c = 0x80;
以上两句是一回事。

如下几种情况:

char c=128;
printf(“%u\n”, c); //按%u输出,结果为 4294967168
printf(“%d\n”, c); //按%d输出,结果为 -128
printf(“%c\n”, c);//按%c输出,结果为空

原因:

c 是一个字符的长度,但当它被传送到printf函数的参数时,是将c按照int来扩张传给printf的。
128 即为二进制的 1000 0000,16进制的0x80, 当它扩展为 int时,由于int可能是4个字节,所以会进行符号扩展。由于 128最高为是1,为负数,扩展为int的-128为11111111 111111 111111 1000000,即0xffffff80

而0xffffff80按照有符号的int来说,就是-128。
而按照无符号的int来说,就是十进制的 4294967168。

    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、短数据类型扩展为长数据类型

(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;

2、长数据类型缩减为短数据类型

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

事实上下面代码会输出 ‘0’

    int a = 0xAA30;
    char c = a;
    printf("%c",c);

3、同一长度的数据类型中有符号数与无符号数的相互转化

直接将内存中的数据赋给要转化的类型,数值大小则会发生变化,因为以不同类型解释同一段内存数据会得到不同的数值。比如一个字节中存放的数据是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来解释的话,就是232−1−127=4294967168。

四、为什么会在前面补1?

开始的char c 是 1000 0000b,后来变成 11111111 11111111 11111111 1000000b,为什么要在前面补1呢?

或者举例,char c 是 1000 0001b,后来变成 11111111 11111111 11111111 1000001b

因为要使 -2^31+2^30+…+2^7+0+1 = -2^7+0+1
也就是 -2^31+2^30+…+2^8 = -2*2^7
也就是 -2^31+2^30+…+2^8+2*2^7 = 0

-2^31+2^30+…+2^8+2*2^7
= -2^31+(2^31-1)-(2^6+2^5+…+1)+2^7 = 0

—END—


参考文献

[1] http://blog.csdn.net/k346k346/article/details/50072445

时间: 2024-09-20 05:59:34

char c=128;printf("%d",c);问题的相关文章

PostgreSQL实现MySQL"insertignore"语法

          对MySQL熟悉的人可能都知道,MySQL 有一个"insert ignore" 语法来忽略已经存在的记录. PostgreSQL暂时不提供这样的语法,但是可以用其他方法来代替. t_girl=# d insert_ignore Table "ytt.insert_ignore" Column | Type | Modifiers ----------+------------------------+----------- id | integ

信息- VBScript 运行时错误 类型不匹配: '[string: ""]' line 12

问题描述 VBScript 运行时错误 类型不匹配: '[string: ""]' line 12 <%Option Explicit%> <%dim cartstrcartstr = getCartFromCookie()if (cartstr=NULL or cartstr ="""") then response.redirect ""Cart.asp"" response.ende

ruby中printf &amp;quot;%x&amp;quot;%-4为何会打印开头..

    先看一下ruby中printf "%x" % -4的返回结果: irb(main):134:0> printf "%x\n" % -4 ..fc 前面的..是神马东东???看了matz的文章略知了一二.     在ruby中如果是x86则Fixnum是32位,如果是x64则Fixnum是64位,超过长度的数字会变为Bignum.在Bignum内部,分别保存符号和绝对值,绝对值以整数数组形式存放,数组的元素是若干32位无符号整数.而Bignum符号另外保

error-mysql InnoDB: Error: &amp;amp;quot;mysql&amp;amp;quot;.&amp;amp;quot;innodb_table_stats

问题描述 mysql InnoDB: Error: "mysql"."innodb_table_stats 附上错误日志: 2015-06-23 22:39:06 1252 [Note] Giving 0 client threads a chance to die gracefully 2015-06-23 22:39:06 1252 [Note] Shutting down slave threads 2015-06-23 22:39:06 1252 [Note] For

major=$(awk &amp;quot;//$2= =/&amp;quot;$module/&amp;quot; {print //$1}&amp;quot; /proc/devices)正确理解。

Normal 0 7.8 磅 0 2 false false false MicrosoftInternetExplorer4 major=$(awk "//$2= =/"$module/" {print //$1}" /proc/devices) 正确理解 导语:        这条语句来自O'REILLY <LINUX设备驱动第三版>字符设备章节的自动创建设备文件脚本代码.网上所有的O'REILLY <LINUX设备驱动第三版>的电子书上

请别再拿“String s = new String(&amp;quot;xyz&amp;quot;);创建了多少个String实例”来面试了吧

这帖是用来回复高级语言虚拟机圈子里的一个问题,一道Java笔试题的. 本来因为见得太多已经吐槽无力,但这次实在忍不住了就又爆发了一把.写得太长干脆单独开了一帖. 顺带广告:对JVM感兴趣的同学们同志们请多多支持高级语言虚拟机圈子  以下是回复内容.文中的"楼主"是针对原问题帖而言. =============================================================== 楼主是看各种宝典了么--以后我面试人的时候就要专找宝典答案是错的来问,方便筛人

报错Syntax error on token &amp;quot;int&amp;quot;, Dimensions expected after this token

ArrayList<int> List = new ArrayList<int>(); 报错Syntax error on token "int", Dimensions expected after this token 原因:引用类型和原始类型没有搞清楚! Java提供两种不同的类型:引用类型和原始类型(或内置类型).Int是java的原始数据类型,Integer是java为int提供的封装类.Java为每个原始类型提供了封装类.   原始类型封装类 boo

visual-char *ptr[N]={&amp;amp;quot;pascal&amp;amp;quot;,&amp;amp;quot;basic&amp;amp;quot;

问题描述 char *ptr[N]={"pascal","basic" char *ptr[N]={"pascal","basic","fortran","java","visual c"};指针被直接赋值为字符串 ptr[N]明明是指针啊 解决方案 这是字符串常量指针的定义 char *ptest = "abc"; 解决方案二: "12

printf-怎么理解指针运算符&amp;amp;quot;*&amp;amp;quot;和自增&amp;amp;quot;++&amp;amp;quot;的应用?

问题描述 怎么理解指针运算符"*"和自增"++"的应用? 例:int a[5]={11,22,33,44,55}; int p=a; printf("*p++ = %dn",*p++); printf("++p = %dn",*++p); 上面的例子,输出结果都不一样,但它们优先级都是自右向左结合,该怎么理解? 请大神指点迷津,感谢!!!! 解决方案 这个问题主要还是理解 ++ 的功能,与 * 与 ++ 的执行优先级. ++