[问题] printf & 型态转换

楼主: vvrr (vvrr)   2016-02-15 14:51:38
开发平台(Platform): (Ex: VC++, GCC, Linux, ...)
GCC
问题(Question):
printf的结果会根据型态的不同而改变
喂入的资料(Input):
int a = 5000;
char b = (char)a;
printf("b = %x\n", b);
预期的正确结果(Expected Output):
b = 88 (5000 = 0x1388)
错误结果(Wrong Output):
b = ffffff88
补充说明(Supplement):
尝试了一些a的初始值和结果,有点不太明白为什么会变成这样,整理如下:
int a = 5000;
作者: longlongint (华哥尔)   2016-02-15 15:05:00
char的范围是?
作者: andrenvq57 (喂!威,喂?)   2016-02-15 15:17:00
为什么不是0x000088而是0xffff88 overflow是直接用ff顶替吗
作者: stupid0319 (征女友)   2016-02-15 15:20:00
char* b = (char*)&a; 这样比较理想结果不是b = ffffff88吗,怎么下一行又变b = ffffff34
楼主: vvrr (vvrr)   2016-02-15 15:37:00
是88没错@@ 抱歉
作者: stupid0319 (征女友)   2016-02-15 15:42:00
char = 0x7F ,0x80 , 0x81 各试看看吧
楼主: vvrr (vvrr)   2016-02-15 15:43:00
char就,一般的char. 应该是-128~1272F,我也不知道为什么是ff,gcc印出来的..
作者: CoNsTaR ((const *))   2016-02-15 15:45:00
因为你 printf 要求的输入不是 char 你却给他 char 吧…它需要一个比 char 更大的型态像你这里输出的结果是 4*8=32bit 的型态
楼主: vvrr (vvrr)   2016-02-15 15:48:00
如果前面都会被补成ffff就还好,但是有些就不会
作者: CoNsTaR ((const *))   2016-02-15 15:49:00
int i = 5000;char c = (char)i;i = c;printf("%p\n", i);@vvrr因为你不能知道你读超过b之外的值是多少啊如果b前面的变量刚好都是0那读出来当然就不会有f 反之亦然这里没有 overflow 只有 overbound
作者: stupid0319 (征女友)   2016-02-15 16:04:00
FFFFFF不是补上去的吧......看了我都快吐血了神人来说一下char跟int的负数怎么表示吧char跟int的-1各为FF跟FFFFFFFF-2呢,FE跟FFFFFFFE所以char的0x88跟int的0xffffff88是等值的在一些程式中,输入0x80000000可能造成bug很多游戏的洗钱BUG就是这么来的
作者: LPH66 (-6.2598534e+18f)   2016-02-15 16:19:00
关键字: sign extension
作者: besmartAE (*无敌海滩男孩*)   2016-02-15 16:21:00
(unsigned char)才对
作者: stupid0319 (征女友)   2016-02-15 16:21:00
一个道具10万块钱好了,买21475个,变成0x80003FE0买了道具后系统还要付给你21亿
楼主: vvrr (vvrr)   2016-02-15 16:36:00
“所以char的0x88跟int的0xffffff88是等值的”所以printf会先把后面的数字转成int吗?^^^^^^^^^^ 后面的char型态的b
作者: stupid0319 (征女友)   2016-02-15 16:40:00
%x Unsigned hexadecimal integer
作者: apologize (人生在世很惬意)   2016-02-15 18:21:00
unsigned char b = (char)a; 改成
作者: LPH66 (-6.2598534e+18f)   2016-02-15 22:26:00
>vvrr 16:36 是, 不过不是 printf 转的而是因为 printf 属于可变参数函式, 不到 int 等级的整数规定要转成 int 再传进去, 所以在那时就已经转了也因为规定转成 int, 所以会转成一个有号整数这才用上了我上面讲的 sign extension概念上就是如 stupid0319 讲的, 0x88 (等于十进制 -120)会变成 int 的 -120 (0xffffff88)那因为二进制观点来看就是最高位的正负号位元往前补满所以要说“ffffff 是补上去的”技术上来说也没有错就是了
作者: azter (Yilin)   2016-02-16 01:00:00
其实可以开小算盘的程式设计师模式第一步计算5000+128第二步 将第一步结果 mod 256第三步 将第二步的结果再减去减去128小算盘的输出结果是-120单看-120可能看不出端倪,请看小算盘下面显示一堆1 0那栏
作者: LPH66 (-6.2598534e+18f)   2016-02-16 03:30:00
要讲型态转换的话, 这样操作: (1) 左下角选 dword, 10 进位然后输入 5000; (2) 左下角点选 byte; 这等同于转型成 char你会看到它变成了 -120 了(3) 根据我上面说的, 传进 printf 前会再转成 int所以再点回 dword, 你会看到数值还是 -120但下面的二进制显示部份前面却是全部补了 1 进去(4) 输出成 %x, 所以点选 16 进位, 就看到 ffffff88 出来了你把你实验的值代换掉上面的 5000, 观察下面二进制显示就会知道为什么有些数会这样变有些数会那样变
楼主: vvrr (vvrr)   2016-02-16 10:58:00
谢谢大家<(_ _)>1. int a 转成 char b的时候,不论正负只留最后1个byte2. char b传进printf前会根据b此时代表数值转成signed int3. printf实际上印出来的都是int.有些只看到1byte的只是前面都是0(而且我没有叫printf印出来) 大概是这样没错吧

Links booklink

Contact Us: admin [ a t ] ucptt.com