Integer Promotion造成两种执行结果
首先我们来看看两段代码及其相应的执行结果。
#include <iostream>
using namespace std;
int main()
{
signed int a = -1;
unsigned int b = a;
if(a == b)
cout<<"a==b"<<endl;
else if(a<b)
cout<<"a < b"<<endl;
else
cout<<"a > b"<<endl;
return 0;
}
执行结果如下:
a==b
#include <iostream>
using namespace std;
int main()
{
signed char a = -1;
unsigned char b = a;
if(a == b)
cout<<"a==b"<<endl;
else if(a<b)
cout<<"a < b"<<endl;
else
cout<<"a > b"<<endl;
return 0;
}
执行结果如下:
a < b
好了,看完两段代码之后我们可以发现两段代码的区别只有a,b两个变量的数据类型。在第一段代码中,a是signed int型,b是unsigned int型,执行完的结果是a == b;在第二段代码中,,a是signed char型,b是unsigned char型,执行完的结果是a < b。
为什么两段代码的执行结果会有不同呢?明明只有数据类型不同。这可能是说明了不同的数据类型在进行比较运算时,编译器会对他们进行的不同的处理方式?
首先我们来分析下第一段代码为什么是输出a==b。假设我的系统中int类型占用4个字节,那么a=-1在内存中的位储存形式是0xffffffff(补码),那么把signed int类型的a赋值给unsigned int类型的b,是直接把a在内存中的位储存形式0xffffffff拷贝给b,那么b在内存中的位储存形式也是0xffffffff,这里我们再对a和b进行比较运算,由于内存中的位形式的相同的,所以输出a==b。但是这里还是需要注意一点,假如我们用代码输出a,b的数值
cout<<a<<","<<b<<endl;
那么输出结果是:
-1,4294967295
这里我就不解释了。
接下来我们来看看上面第二段代码。为什么输出结果会是a < b呢?怎么理解?查完资料后,我找到了这个问题出现的原因。
原来是在对char型的变量进行比较运算时(a > b,a < b,a==b这些比较运算),编译器首先会对char型变量进行Integer Promotion,也就是将char型变量提升成int类型的,然后再进行比较,至于提示的方法,是根据原始类型进行位扩展(如果原始类型为unsigned,进行零扩展,如果原始类型为signed,进行符号位扩展)到32位。拿上文第二段代码作为例子,a是signed char型的,a=-1在内存中的位储存形式是0xff,把a赋值给b的过程同上面的int类型的;然后就是a与b进行比较运算了,编译器会把a,b都提升到int类型,那么原来a在内存中的位形式是0xff,提升为int类型后会变成0xffffffff(符号位扩展),原来b在内存中的位形式是0xff,提示为int类型后会变成0x000000ff(零扩展),可以看出,此时a是小于b的。等等?a < b?对的,没错,a是小于b的,因为Integer Promotion之后,a,b都暂时(只是暂时,仅仅只是在执行运算时提升了)提升为int类型了,也就是signed int类型。
发现这个问题后,我又了解了一下Integer Promotion,其实不仅仅只是在比较运算时会进行Integer Promotion,只要是进行运算时(赋值,算术运算,逻辑运算),编译器发现运算的某个变量的位宽不足int类型的位宽那么就会进行提升。比如
char a += 1;
这个其实中间已经有Integer Promotion了。
其实到这里我还是有满腔的疑问,比如,为什么编译器要进行Integer Promotion?其实我对这个问题是有所想法的了,不过由于最近比较忙,我也没有时间去证实我的猜想,不过在这里跟大家分享一下我的想法。
为什么要有Integer Promotion?
学过微机原理或者学习过汇编的同学可能会知道,在我们的CPU中有一个算术逻辑单元(Arithmetic&logical Unit),简称ALU,主要功能是进行二位元的算术运算,如加减乘(不包括整数除法)和寄存器中的值之间的逻辑运算。那么,我们的C/C++程序进行的运算最终也是要在ALU中进行的,以32位CPU为例,寄存器都是32位的(刚好是一个int类型所占用的位数),想要把char类型的变量送进ALU中运算,那必然是需要把char类型变成32位,然后通过32位寄存器送入ALU,那么这个时候Integer Promotion的意义就出来了,如果不这样进行提升,ALU就无法对char类型的变量进行运算了。基本上,在所有现代CPU体系结构中,二进制都以补码的形式来表示,自然ALU就是针对补码设计的,所以Integer Promotion操作把char变量提升为signed int类型也是CPU的结构所决定的(32位的寄存器决定了是整型的,ALU决定了需要有补码形式的,所以只能是signed int)。
好了,上面的想法是根据我目前所学的知识进行的解释,如果有大神看到不对的地方希望可以及时帮我纠正。