寄存器溢出问题
本帖最后由 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 idivl0x1c(%esp)
8048430: 88 44 24 2f mov %al,0x2f(%esp)
我的疑问:
short类型的c变量,为什么在运算(c+1)*100中使用%eax寄存器,而不使用%ax寄存器?
有什么方法可以控制使用寄存器的类型吗?例如编译选项之类的。
谢谢!
(c + 1) * 100 是int型数据,为什么要溢出?
你要控制位数,可以用
x=1013414;
x&=0xff; //低8位 回复 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
回复 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 idivl0x1c(%esp)
804844b: 88 44 24 2f mov %al,0x2f(%esp) 回复 3# dxcheng
在char r = (c + 1) * 100 / (a + 1);中, 1和·100·是int·型的。
所以, 你改成:char r = (c + (short)1) * (short)100 / (a + (short)1);试试。
其实, 前面帖子中我想说的是, 在程序中假定short是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
虽然使用32位寄存器,但实际只用其中低16位,高位为空
页:
[1]