首页
社区
课程
招聘
7
[原创]一个C里容易忽略的细节
发表于: 2009-8-11 20:21 10878

[原创]一个C里容易忽略的细节

2009-8-11 20:21
10878

今天发现了一个C里容易忽略的细节。
由于这个小细节,我的程序调试了半天,耽误了不少功夫。
现在拿出来和大家分享一下~共同进步~。

首先,VC下的,一个很简单的程序

# include <stdio.h>

int main ()
{
        short int a ;

        a = 0x8000 ;

        if (a == 0x8000)

                printf ("T\n") ;

        else

                printf ("F\n") ;

        return 0 ;
}

大家猜才结果是什么呢?
答案是F。

如果你认为是T,呵呵,最好自己调试一下,找到原因,不太难的,找不到的话再往下看~~

(如果你认为本来就是F,理由是short int 的范围是-32768到32767,这里0x8000是32768,溢出了,不相等,那么,不好意思,你的理解有偏差。不信你把short int换成int,再把0x8000扩展到0x80000000,同样的问题在int型的时候输出T,怎么解释?~)

这里,a是short int型,占两个字节。当我们把0x8000赋给a后,a中的值为
1000 0000 0000 0000(二进制)

在执行if条件时,程序要把a的值和立即数0x8000进行比较。
但是a的值保存在内存当中,于是程序会将a的值从内存里取到寄存器中(通常是eax)
mov eax, a的地址   ;    这个是假想生成的代码

但是a的值只有2字节,eax有4字节。这里编译器在取的时候做了一个符号扩展:
movsx eax, a的地址    ;  这个是实际生成的代码

这样,编译器其实是拿eax里,也就是a的值符号扩展后,也就是0xffff8000和0x8000进行比较,判定为不相等。

现在,如果把short int 换成int,0x8000换成0x80000000就不会出现判断失误的问题了。因为int和eax是等长的,没有进行符号扩展。

分析完毕。请各位高手拍砖留情~


[招生]科锐逆向工程师培训(2025年3月11日实地,远程教学同时开班, 第52期)!

收藏
免费 7
支持
分享
赞赏记录
参与人
雪币
留言
时间
Youlor
为你点赞~
2024-2-27 00:00
伟叔叔
为你点赞~
2024-1-4 04:47
QinBeast
为你点赞~
2023-12-13 00:00
shinratensei
为你点赞~
2023-10-31 00:03
PLEBFE
为你点赞~
2023-10-11 00:39
心游尘世外
为你点赞~
2023-9-28 04:32
飘零丶
为你点赞~
2023-9-22 00:07
最新回复 (23)
雪    币: 263
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
确实是经过了符号扩展。

挺容易忽略的。
2009-8-11 21:21
0
雪    币: 157
活跃值: (10)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
3
纠正一下

在执行if条件时,程序要把a的值和立即数0x8000进行比较。
但是a的值保存在内存当中,于是程序会将a的值从内存里取到寄存器中(通常是eax)
mov eax, a的地址   ;    这个是假想生成的代码

这里的说法不准确
a会进行符号扩展,是因为
if ( a == 0x8000)右边的0x8000程序认为是一个int型(可以用sizeof(0x8000)来证实)
所以这里不等长数进行比较,才会进行符号扩展,这个概念叫做整形提升。
刚刚我老师告诉我的。。
2009-8-12 00:00
0
雪    币: 15
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
会吗?试了结果输出是T啊,,不是F
2009-8-12 08:27
0
雪    币: 15
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
环境 VC6 ,WIN XP SP3
2009-8-12 08:28
0
雪    币: 389
活跃值: (92)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
楼主,好像不对吧,short int最大表示范围:-32768到32767 ,可是int类型的表示范围也是-32768到32767,a=0x8000,也就是32768,发生溢出了,结果当然为F了,不知道理解对不对!请指教
2009-8-12 21:40
0
雪    币: 136
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
这样的错误不是很烦人
2009-8-13 00:05
0
雪    币: 306
活跃值: (153)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
8
楼主很细心, 这个很容易忽略
2009-8-24 22:29
0
雪    币: 262
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
这个是基础.
相当基础的东西,不过越是基础的越容易被忽视.
2009-8-26 11:09
0
雪    币: 4560
活跃值: (1012)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
10
很好,又学了一招,谢谢楼主了
2009-8-26 11:12
0
雪    币: 397
活跃值: (938)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
学习了 确实没注意到
2009-8-26 11:26
0
雪    币: 110
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
楼主很细心  学习了
2009-8-26 11:36
0
雪    币: 256
活跃值: (1028)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
13
请楼主给出修正版本
2009-8-26 12:19
0
雪    币: 251
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
说明最好不要把Signed和Unsigned进行比较
2009-8-26 12:30
0
雪    币: 370
活跃值: (52)
能力值: ( LV13,RANK:350 )
在线值:
发帖
回帖
粉丝
15
从高级语言的角度来看 这样理解是没错的 你完全可以把0xffff8000看成-32768的 加个unsigned 就可以了
那int 0x80000000为什么没溢出呢 只能说是c高级语言理论体系和编译器(主要是计算机系统的关系)之间的摩擦吧
我是这样理解的 仅供参考
2009-8-26 13:04
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
支持!
2009-8-26 13:52
0
雪    币: 157
活跃值: (10)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
17
回8楼:修正的方式就是定义成unsigned short int型。

回斑竹:


呵呵,这就是我没有在文章里写理解错误,而是写的理解有偏差的原因了。从高级语言的角度来看,这样的确是溢出了,但是溢出不足以解释这种现象,不够低层。

另外,我想说一下,为什么编译器会进行符号扩展。因为这里有一个概念:整形提升。所谓整形提升,就是运算符一边是整形,另一边是小于整形的类型,则需将较小的类型提升成整形再进行比较。如short int a ;
if (a == 0x80)这里,运算符'=='的左边是short int型,右边的0x80常数被认为是int型。编译器会将short int型扩展成int型再做比较。因为a是signed的,所以进行符号扩展了。
2009-8-26 14:30
0
雪    币: 247
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
解释很好。
学习了

2009-8-26 14:51
0
雪    币: 38
活跃值: (57)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
19
d:\backup\我的文档\workshop ii\test\test.cpp(7) : warning C4305: '=' : truncation from 'const int' to 'short'
d:\backup\我的文档\workshop ii\test\test.cpp(7) : warning C4309: '=' : truncation of constant value
2009-8-27 08:24
0
雪    币: 157
活跃值: (10)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
20
对于这个问题,从我来说,一般是不会去注意关于类型转换的warning的。另外。。我的VC真的没有报warning。。。还有,有时候就算有了warning,我们也想知道这样会产生什么后果,和想象中的是否一样,以及这种后果的原因。因为同样一个知识点,也许在这里产生warning,但是在别的情况下就不会有提示。我们必须去了解它的内部到底是如何运转的。
2009-8-27 10:43
0
雪    币: 1885
活跃值: (722)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
确实是比较容易忽略的问题,学习到了,呵呵
2009-8-27 12:49
0
雪    币: 1
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
楼主很善于发现
2009-8-27 15:25
0
雪    币: 206
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
如果你定义为unsigned or signed,直接指明是什么,它就不会出现这样的错误了。
而是你没有指明,所以用默认的东西出现的错误。
教训是:不要想当然。
2009-9-3 14:48
0
雪    币: 437
活跃值: (383)
能力值: ( LV12,RANK:240 )
在线值:
发帖
回帖
粉丝
24
越界成了负数了。。
2009-9-3 14:57
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册