免费注册 查看新帖 |

ChinaUnix.net

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 4339 | 回复: 7

[C] 寄存器溢出问题 [复制链接]

论坛徽章:
0
发表于 2016-03-07 13:19 |显示全部楼层
本帖最后由 dxcheng 于 2016-03-08 09:19 编辑

运行如下demo,本来以为会出现寄存器溢出的问题,不过实际结果却不是,还请大牛们多多指教,谢谢!

// test.c
int main()
{
    short c = 327;
    short a = c * 2;
    char r = (c + 1) * 100 / (a + 1); // (c+1)*100 本来以为这里的寄存器会产生溢出,事实上没有溢出
    // short类型的范围是-32768~+32767,如果c = 327,则(c + 1) * 100 = 32800,超过无符号short类型的取值范围,因此溢出。

    printf("sizeof(short):%d, sizeof(char):%d, sizeof(int):%d\n",
        sizeof(short), sizeof(char), sizeof(int));
    printf("r:%d\n", r);
    return 0;
}

运行结果:
$gcc --version
gcc (GCC) 4.4.6 20120305 (Red Hat 4.4.6-4)
$gcc test.c -o test -g
$./test   
sizeof(short):2, sizeof(char):1, sizeof(int):4
r:50

反汇编的结果:
int main()
{
80483f4:       55                      push   %ebp
80483f5:       89 e5                   mov    %esp,%ebp
80483f7:       83 e4 f0                and    $0xfffffff0,%esp
80483fa:       83 ec 30                sub    $0x30,%esp
    short c = 327;
80483fd:       66 c7 44 24 2a 47 01    movw   $0x147,0x2a(%esp)
    short a = c * 2;
8048404:       0f b7 44 24 2a          movzwl 0x2a(%esp),%eax
8048409:       01 c0                   add    %eax,%eax
804840b:       66 89 44 24 2c          mov    %ax,0x2c(%esp)
    char r = (c + 1) * 100 / (a + 1);
8048410:       0f bf 44 24 2a          movswl 0x2a(%esp),%eax
8048415:       83 c0 01                add    $0x1,%eax
8048418:       6b c0 64                imul   $0x64,%eax,%eax
804841b:       0f bf 54 24 2c          movswl 0x2c(%esp),%edx
8048420:       83 c2 01                add    $0x1,%edx
8048423:       89 54 24 1c             mov    %edx,0x1c(%esp)
8048427:       89 c2                   mov    %eax,%edx
8048429:       c1 fa 1f                sar    $0x1f,%edx
804842c:       f7 7c 24 1c             idivl  0x1c(%esp)
8048430:       88 44 24 2f             mov    %al,0x2f(%esp)

我的疑问:
short类型的c变量,为什么在运算(c+1)*100中使用%eax寄存器,而不使用%ax寄存器?
有什么方法可以控制使用寄存器的类型吗?例如编译选项之类的。

谢谢!

论坛徽章:
59
2015年亚洲杯之约旦
日期:2015-01-27 21:27:392015年亚洲杯之日本
日期:2015-02-06 22:09:41拜羊年徽章
日期:2015-03-03 16:15:432015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:50:282015元宵节徽章
日期:2015-03-06 15:50:392015年亚洲杯之阿联酋
日期:2015-03-19 17:39:302015年亚洲杯之中国
日期:2015-03-23 18:52:23巳蛇
日期:2014-12-14 22:44:03双子座
日期:2014-12-10 21:39:16处女座
日期:2014-12-02 08:03:17天蝎座
日期:2014-07-21 19:08:47
发表于 2016-03-07 19:53 |显示全部楼层
(c + 1) * 100 是int型数据,为什么要溢出?
你要控制位数,可以用
x=1013414;
x&=0xff; //低8位

论坛徽章:
0
发表于 2016-03-08 08:56 |显示全部楼层
回复 2# folklore


c是short类型,是不是应该用%ax来存放c的值,现在是用的%eax,所以没有溢出。
我的疑惑是为什么用%eax寄存器,而不是用%ax寄存器,谢谢!

char r = (c + 1) * 100 / (a + 1);
8048410:       0f bf 44 24 2a          movswl 0x2a(%esp),%eax
8048415:       83 c0 01                add    $0x1,%eax

论坛徽章:
0
发表于 2016-03-08 09:17 |显示全部楼层
回复 2# folklore


为了避免常量1和100的影响,我把这两个数先定义为short类型,不过结果还是一样的,还是使用的%eax寄存器。

PS:我说的溢出是指的short类型的范围是-32768~+32767,如果c = 327,则(c + 1) * 100 = 32800,超过无符号short类型的取值范围,因此溢出。


int main()
{
80483f4:       55                      push   %ebp
80483f5:       89 e5                   mov    %esp,%ebp
80483f7:       83 e4 f0                and    $0xfffffff0,%esp
80483fa:       83 ec 30                sub    $0x30,%esp
    short c = 327;
80483fd:       66 c7 44 24 26 47 01    movw   $0x147,0x26(%esp)
    short a = c * 2;
8048404:       0f b7 44 24 26          movzwl 0x26(%esp),%eax
8048409:       01 c0                   add    %eax,%eax
804840b:       66 89 44 24 28          mov    %ax,0x28(%esp)
    short n1 = 1;
8048410:       66 c7 44 24 2a 01 00    movw   $0x1,0x2a(%esp)
    short n100 = 100;
8048417:       66 c7 44 24 2c 64 00    movw   $0x64,0x2c(%esp)
    char r = (c + n1) * n100 / (a + n1);
804841e:       0f bf 54 24 26          movswl 0x26(%esp),%edx
8048423:       0f bf 44 24 2a          movswl 0x2a(%esp),%eax
8048428:       01 c2                   add    %eax,%edx
804842a:       0f bf 44 24 2c          movswl 0x2c(%esp),%eax
804842f:       0f af c2                imul   %edx,%eax
8048432:       0f bf 4c 24 28          movswl 0x28(%esp),%ecx
8048437:       0f bf 54 24 2a          movswl 0x2a(%esp),%edx
804843c:       01 d1                   add    %edx,%ecx
804843e:       89 4c 24 1c             mov    %ecx,0x1c(%esp)
8048442:       89 c2                   mov    %eax,%edx
8048444:       c1 fa 1f                sar    $0x1f,%edx
8048447:       f7 7c 24 1c             idivl  0x1c(%esp)
804844b:       88 44 24 2f             mov    %al,0x2f(%esp)

论坛徽章:
59
2015年亚洲杯之约旦
日期:2015-01-27 21:27:392015年亚洲杯之日本
日期:2015-02-06 22:09:41拜羊年徽章
日期:2015-03-03 16:15:432015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:50:282015元宵节徽章
日期:2015-03-06 15:50:392015年亚洲杯之阿联酋
日期:2015-03-19 17:39:302015年亚洲杯之中国
日期:2015-03-23 18:52:23巳蛇
日期:2014-12-14 22:44:03双子座
日期:2014-12-10 21:39:16处女座
日期:2014-12-02 08:03:17天蝎座
日期:2014-07-21 19:08:47
发表于 2016-03-08 09:56 |显示全部楼层
回复 3# dxcheng

  1. char r = (c + 1) * 100 / (a + 1);
复制代码
中, 1和·100·是int·型的。

所以, 你改成:
  1. char r = (c + (short)1) * (short)100 / (a + (short)1);
复制代码
试试。

其实, 前面帖子中我想说的是, 在程序中假定short是16位是不对的。。。
所以要自已用代码保证位数。


论坛徽章:
0
发表于 2016-03-08 11:16 |显示全部楼层
回复 5# folklore


Thanks anyway.

1. 强制转换为short也还是用的%eax

  char r = (c + (short)1) * (short)100 / (a + (short)1);
804841e:       0f bf 44 24 26          movswl 0x26(%esp),%eax
8048423:       83 c0 01                add    $0x1,%eax

2. short类型的长度16位在代码中是有验证的
$./test
sizeof(short):2, sizeof(char):1, sizeof(int):4
r:50



论坛徽章:
0
发表于 2019-01-08 23:47 |显示全部楼层
虽然使用32位寄存器,但实际只用其中低16位,高位为空

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

基于案例的 SQL 优化实战训练营

讲师:中电福富特级专家梁敬彬,参与本次课程培训,你将收获:
1. 能编写出较为高效的 SQL;
2. 能解决70%以上的数据库常见优化问题;
3. 能得到老师提供的高效的相关工具和解决方案;
4. 能举一反三,收获不仅仅是 SQL 优化。
现在购票享受8.8折优惠!
----------------------------------------
优惠时间:2019年3月20日前

大会官网>>
  

北京盛拓优讯信息技术有限公司. 版权所有 16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122
中国互联网协会会员  联系我们:huangweiwei@it168.com
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP