整形提升与溢出

来源:互联网 发布:中日技术贸易 数据 编辑:程序博客网 时间:2024/05/11 21:08

1、整形提升

表达式进行计算时,变量如果能用int表示,就用int表示,如果不能用int表示,就用usigned int表示。 

这是因为寄存器的长度和int长度一致。

到底是用int还是unsigned int,取决于编译器。举一个例子:

char c = 0xb0;

if(c==0xb0){

...

}

c在参与运算的时候, 0xb0 = 01011 00000, 编译器会解释上述代码为:

mov al, 0xb0

movsz edx, al             //将al进行带符号扩展,扩展完成后0xff ff ff b0

cmp edx, 0xb0           //将0xff ff ff b0 和0xb0,进行32位比较,不等恒成立。



2、整形溢出

根据规则1, 计算机运算都可理解成整形的运算,其他类型的一般都会进行符号位扩展成32位进行运算,那么溢出规则可以简单的理解为:

2.1 无符号的整形溢出规则

结果 = 理论值 mod (2 ^ 寄存器长度),也可以简单理解为高位舍弃。

假设CPU为8位机, 定义2个char类型的变量:

x = 130; y = 131;

由于寄存器最大长度8, 则最大能表示的255, 而x+y =261 = 0b1 0000 0101

结果 = 261 mod (2 ^ 8) = 5, 或者理解为 0b1 0000 0101 舍弃高位:0b101 = 5


2.2 有符号整形溢出规则

在各个平台上支持不一样,C语言规定为不可预测。(经测试,在x86上也是高位舍弃)


3、例子分析

int main(){char c = -20;unsigned int a = 6;printf("%d\n", ((c+a)>1));}

输出居然为-14, 1,不理解? 看汇编


c的机器码为:0xec, 由于字符在内存中是以数字存贮的,且只占一个字节,在整形提升中,为保证数字值不变,高位全部扩展为1,那么, (c+a)= oxfffffff2 >1 成立。因为cpu是通过补码运算,实际cpu运算有兴趣的可以自己验证。
例二:

int main(){char c = -20;int a = 6;    //去掉unsignedprintf("%d\n", ((c+a)>1));}
这次输出为0 

从上面看出,在char 和 int 进行cpu运算时, 全部都是用4字节来存贮,都是调用的带符号扩展movsz,负值高位填充为1,正值高位扩展为0
区别只在于 例子1后面调用setg, 例子二调用的seta

seta al含义:al =  ~CF & ~ZF = 1
setg al含义: al = ~(SF ^OF) & ZF  = ~(1 ^ 0) & 0 = 0

从这个例子可以也看出, 所谓整形提升,以及所谓的有符号和无符号相加的问题,都只与编译器有关,编译器根据语法规则生成对应体系架构的机器码,
CPU在其中的作用,只是进行运算以及运算中对各个标志位赋值而已。


0 0
原创粉丝点击