【C/C++】鲜为人知的知识--Integer Promotion

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)。

好了,上面的想法是根据我目前所学的知识进行的解释,如果有大神看到不对的地方希望可以及时帮我纠正。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据您提供的Makefile,这个错误信息是由于在删除目标文件时出现问题引起的。这可能是由于您的Dev-C++环境配置不正确导致的。 在您的Makefile中,您使用了`$(DEL)`变量来执行删除操作。然而,在Windows环境下,删除操作通常使用`del`命令而不是`devcpp.exe INTERNAL_DEL`。 为了解决这个问题,您可以尝试将以下行: ``` DEL = C:\Program Files (x86)\Embarcadero\Dev-Cpp\devcpp.exe INTERNAL_DEL ``` 替换为: ``` DEL = del ``` 这将使用Windows的`del`命令来执行删除操作。 修改后的Makefile如下所示: ```makefile # Project: 项目1 # Makefile created by Embarcadero Dev-C++ 6.3 CPP = g++.exe CC = gcc.exe WINDRES = windres.exe OBJ = main.o LINKOBJ = main.o LIBS = -L"C:/Program Files (x86)/Embarcadero/Dev-Cpp/TDM-GCC-64/lib" -L"C:/Program Files (x86)/Embarcadero/Dev-Cpp/TDM-GCC-64/x86_64-w64-mingw32/lib" -static-libgcc INCS = -I"C:/Program Files (x86)/Embarcadero/Dev-Cpp/TDM-GCC-64/include" -I"C:/Program Files (x86)/Embarcadero/Dev-Cpp/TDM-GCC-64/x86_64-w64-mingw32/include" -I"C:/Program Files (x86)/Embarcadero/Dev-Cpp/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/9.2.0/include" CXXINCS = -I"C:/Program Files (x86)/Embarcadero/Dev-Cpp/TDM-GCC-64/include" -I"C:/Program Files (x86)/Embarcadero/Dev-Cpp/TDM-GCC-64/x86_64-w64-mingw32/include" -I"C:/Program Files (x86)/Embarcadero/Dev-Cpp/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/9.2.0/include" -I"C:/Program Files (x86)/Embarcadero/Dev-Cpp/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/9.2.0/include/c++" BIN = 项目1.exe CXXFLAGS = $(CXXINCS) -std=c++11 CFLAGS = $(INCS) -std=c++11 DEL = del .PHONY: all all-before all-after clean clean-custom all: all-before $(BIN) all-after clean: clean-custom ${DEL} $(OBJ) $(BIN) $(BIN): $(OBJ) $(CPP) $(LINKOBJ) -o $(BIN) $(LIBS) main.o: main.cpp $(CPP) -c main.cpp -o main.o $(CXXFLAGS) ``` 请尝试使用修改后的Makefile重新编译您的项目,看看是否能够解决问题。如果还有其他错误信息,请提供详细的错误信息,以便我更好地帮助您解决问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值