为什么C语言会有整型提升(Integral Promotion)?

时间:2022-11-17 11:59:15


C语言中的短整型(如char、short、bit-field和enum等长度小于32位的整数),在参与运算之前,首先会被提升为 int 或 long(signed 或 unsigned)类型,这就是C语言整型提升的过程。

为什么需要整型提升?

C语言是直接与机器指令关联的,C语句最终被翻译成机器指令,在CPU指令集中不一定有短整型的运算指令,比如 ARM、RV32 只有32位的运算指令;ARM64、RV64只有32位和64位的运算指令。所以短整型的运算不能直接被翻译成机器指令,只能首先提升成 int(32位)或 long(64位)类型才能被翻译成机器指令。如果最终结果需要的是短整型,那么再用 and 或 sll、slr 指令把高位清零。

C语言的int可能是16位,也可能是32位。int的位宽通常与CPU的寄存器位宽相一致。C语言最早支持的计算机是PDP-11,这是一种16位机,所以int是从16位开始的。后来逐渐发展成了32位机,int就变成32位了。现在的主流是64位机,而int可能是32位,也可能是64位,和编译器及其选项有关,因为现在的64位机是兼容32位数据操作的,也就是说有对32位数据直接进行操作的指令,例如RV64中的addw等指令。一般情况下,64位机的int也是32位的,毕竟可以节省存储空间。

(C语言要求int的位宽在short 和 long 之间,即 sizeof(short) <= sizeof(int) <= sizeof(long),在64位系统中,如果int为64位,那么long也必为64位,short则固定为16位,那么就没有32位的整数类型了,所以int取32位才是合乎常理的。)

所以在64位系统中,如果能生成对应的32位指令,那么短整型被提升为int类型(如ADDW),如果只能生成对应的64位指令(如SLT),那么短整型(甚至包括32位的int)被提升为long类型?

短整型存储在内存中是以声明的长度存储的,一旦加载到寄存器,就被提升到寄存器长度了。编译器会特殊处理高位数据,以确保短整型表现出正确的特性,例如uint8_t的类型不会出现大于0xff的数值(将运算结果&0xff)。

MISRA-C 特别强调整型提升这个事情,主要是因为int的长度不是唯一的,在16位机中,int是16位的,而在32位机中,int是32位的,MISRA-C 希望编写的代码在不同的处理器之间移植的时候得到一致的结果,以此来避免移植带来的缺陷,所以既要考虑32位机也要考虑16位机。

参考资料: