C/C++中规定了一组内置类型的隐式类型转换规则,用于类型不一致的运算过程中。
- 算术运算,如 int + short + double 时,int和short的变量会隐式转换为double,再与double进行加法。
- 关系运算,如 if ( int < unsigned int),会转换为较宽类型的unsigned int
- 赋值运算,如int = double,double的变量将会被截断成int,然后赋值给左边
- 函数返回,如fun()返回值为double,函数实现中,却return int,此时会将int隐式转换为double返回。
- 函数返回后 赋值给变量,如int = fun(),会将fun()返回的double类型转换为int。
算术运算和关系运算的类型转换原则是转换为表达式中的最大宽度的类型。赋值运算和函数返回值相关的 转换原则是 按照目标类型进行转换。
除了上面的隐式类型转换场景,C/C++还规定了另外一种需要进行隐式数据类型转换的场景:整值提升(integral promotion)。如果 表达式(如 算术计算和 关系判断)中的所有数据类型都小于int (小于int的有 枚举类型,bool、char、unsigned char、short ),则会将这些数据类型全部提升为int或unsigned int,提升后再进行表达式计算,计算后再进行截断得到最终结果。这个过程就是整形提升,提升规则:有符号的在左边补上符号位,无符号的在左边补上0。注:如果表达式中有数据类型大于int,其他小于int的类型会隐式转换为表达式中的最大宽度的类型。
整型提升的意义,百度有以下解释:表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。
以下是代码示例,其中,有符号数 char f =-1,在整形提升时,左边高bit补符号位1。无符号数 unsigned char test 在提升时,左边高bit 补0。
#include "stdio.h"
int main(int argc, char** argv)
{
// convert type
// https://blog.youkuaiyun.com/qq_35524916/article/details/61409126
int d = -1;
unsigned int e = 0xffffffff;
char f = -1;
if (d > e)
printf("d > e \n");
else if (d == e) // d convert type to unsigned int
printf("d = e \n");
else
printf("d < e \n");
if (f > sizeof(f)) // f convert to size_t (here is unsigned int), -> 0xffffffff
printf("f > sizeof(f)\n");
// integral promotion
if (f == 0xff)
printf("f == 0xff \n");
else if (f == 0xffffffff)
printf("f promote to signed int \n");
else
printf("error \n");
// integral promotion
// https://blog.youkuaiyun.com/db199410/article/details/51556060
char a = '2';
char b = '4';
char c = a + b;
printf("sizeof (char + char ) = %d \n", sizeof(a + b)); // result : 4
printf("sizeof (c ) = %d \n", sizeof(c)); // result : 1
// integral promotion
unsigned char test = 0xA5;
unsigned char test_1 = ~test >>4+1;
//first, + has high priority than >>
//second, 0xA5 promote to unsigned int 0x000000A5
//third, ~0x000000A5 = 0xFFFFFF5A
//fourth, 0xFFFFFF5A >> 5 = 0x07FFFFFA
//fifth, truncate to 1byte, =0xFA
printf("test_1 = 0x%x \n",test_1);
return 0;
}