整数溢出问题的坑,你真弄明白了吗?

整数溢出问题的坑,你真弄明白了吗?

一 提两个简单问题:

下面代码在64位系统下运行,short 类型占两个字节,int类型占4个字节,long类型占8个字节, 猜猜问题1与问题2的结果:

问题1:以下两个代码的输出结果相同吗

代码一:

int main()

{

short a = 0x7fff;

short b = a + 1;

int c = b;

printf("代码一的输出结果为:%d\n", c);

return 0;

}

代码二:

int main()

{

short a = 0x7fff;

int c = a + 1;

printf("代码二的输出结果为:%d\n", c);

return 0;

}

问题2:以下的代码输出结果又是否相同?

代码三:

int main()

{

int a = 0x7fffffff;

int b = a + 1;

long c = b;

printf("代码三的输出结果为:%ld\n", c);

}

代码四:

int main()

{

int a = 0x7fffffff;

long c = a + 1;

printf("代码四的输出结果为:%ld\n", c);

}

二 猜对答案了没?

问题1内的代码一与代码二的输出结果不同,代码一在执行short b = a + 1语句时发生了short整型溢出问题, 代码二是安全的。它们的执行结果分别如下:

代码一的输出结果:

代码一的输出结果为:-32768

代码二的输出结果:

代码二的输出结果为:32768

问题2内的代码三与代码四分别在执行int b = a + 1和long c = a + 1时都发生了整数溢出问题,它们的执行结果是相同的:

代码三的输出结果:

代码三的输出结果为:-2147483648

代码四的输出结果:

代码四的输出结果为:-2147483648

三 原因分析:

代码一分析:

在代码一内,执行short b = a + 1时发生溢出应该是很容易理解,short最大表示的正整数为0x7fff,加一之后变为了0x8000, 即能表示的最大负整数-32768, 再转换为int类型时,符号位是要保留的,可以还是-32768, 看看它的汇编代码更容易理解:subq $16, %rsp

movw $32767, -12(%rbp)

// 该指令操作之后,eax寄存器的高16位为0补上(movzwl中的z就表示zero),低16的ax的值为32767.

movzwl -12(%rbp), %eax

addl $1, %eax

// 关键: 这里只把ax的值(即相加之后的32768,0x8000)保存到了内存中。

movw %ax, -10(%rbp)

// 下面是在执行short类型到int类型的转换,其中eax中的高16的值是使用符号位进行填充(movswl的s对应sign),0x8000符号位为1.

movswl -10(%rbp), %eax

movl %eax, -8(%rbp)

代码二分析:

在代码二内,当执行int c = a + 1时没有发生short类型的溢出问题, 原因还得从汇编代码层次查找到:subq $16, %rsp

movw $32767, -6(%rbp)

movswl -6(%rbp), %eax // 以符号位填充高16位的数式复制到eax寄存器

addl $1, %eax

movl %eax, -4(%rbp)

代码三分析:

在代码三中,当执行'int b = a + 1`时发生了int整数的溢出,它对应的汇编代码如下所示:subq $16, %rsp

movl $32767, -16(%rbp)

movl -16(%rbp), %eax // 下面三个代码使用eax寄存器执行了加1操作

addl $1, %eax

movl %eax, -12(%rbp)

movl -12(%rbp), %eax

cltq // 下面两行,使用rax寄存器执行了类型转换操作,

movq %rax, -8(%rbp) // cltq执行符号位扩展,把eax扩展为rax,高32使用32位填充。

代码四分析:

在代码四中,当执行'long c = a + 1`时也发生了int整数的溢出,奇怪吧。来看看它对应的汇编代码:subq $16, %rsp

movl $32767, -12(%rbp)

movl -12(%rbp), %eax

addl $1, %eax // 执行相加过程也是使用eax寄存器,因此就溢出了。

cltq

movq %rax, -8(%rbp)

四 如何解决整数溢出问题?

在对操作数执行运算之前,先进行类型转换,而不是执行了运算之后再执行类型转换

例如针对代码四的整数溢出问题,代码修改如下:

int main()

{

int a = 0x7fffffff;

long c = (long)a + 1;

printf("代码四的输出结果为:%ld\n", c);

}

代码修改之后,它对应的汇编代码如下:

subq $16, %rsp

movl $32767, -12(%rbp)

movl -12(%rbp), %eax

cltq

addq $1, %rax

movq %rax, -8(%rbp)

从汇编代码就可以看出来,它不会发生整数溢出了!!

相关推荐

智能电视频繁死机?一文教你如何快速解决!
吱吱作品集
365彩票数据最专业

吱吱作品集

📅 02-05 👁️ 9393
群星Victorious成就怎么达成
s365 2.2.3

群星Victorious成就怎么达成

📅 10-08 👁️ 6179
【关注】植发后多久能见效果?术后护理的“黄金法则”
365彩票数据最专业

【关注】植发后多久能见效果?术后护理的“黄金法则”

📅 09-21 👁️ 1718
饮酒·其七原文、翻译及赏析、拼音版及朗读
魔兽世界猎人稀有猪宝宝大全 WOW猪系宠物盘点
365账号限制投注怎么办

魔兽世界猎人稀有猪宝宝大全 WOW猪系宠物盘点

📅 01-26 👁️ 3287
PTE可以申请香港吗?香港大学PTE成绩要求
s365 2.2.3

PTE可以申请香港吗?香港大学PTE成绩要求

📅 06-30 👁️ 9197
热门的pvp网游排行榜合集 2025经典的pvp游戏汇总
365账号限制投注怎么办

热门的pvp网游排行榜合集 2025经典的pvp游戏汇总

📅 12-01 👁️ 8857
igmp不生效
365账号限制投注怎么办

igmp不生效

📅 08-15 👁️ 1139