1、整数提升
unsigned int Add2(unsigned short a, unsigned short b)
{
return a + b;
}
在32位操作系统下,计算机的寄存器的位宽就是32位
在做运算时,变量 a 和 b 会分别被 push 到寄存器中
由于寄存器位宽为32,因此 变量a 与 变量b 都会被提升到为 unsigned int 类型,这就是整数提升
两个unsigned short类型的参数 相加 结果一定会在unsigned int 范围内,因此 不会有问题
- 在表达式计算时,各种整型首先要提升到 int 类型,如果 int 类型不足以表示则要提升为 unsigned int
类型,然后执行表达式的运算。
整型提升的意义在于:
表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。
2、隐式转换
unsigned short Add(unsigned short a, unsigned short b)
{
return a + b;
}
如上述,寄存器位宽 引起 整数提升,提升后返回类型就是 unsigned int ,
而这段代码 定义 返回类型为 unsigned short ,会进行隐式转换,将 unsigned int 截断到 unsigned short
整数类型之间的转换:
- 显式转换:通过转换语句进行的 。static_cast<新类型>
- 隐式转换:在语句中自动发生的类型转换
发生隐式转换的场景包括:
- 在进行算术或逻辑运算时,使其操作数隐式转换为另一个类型;
- 函数调用时,传入的实参发生隐式转换为另一个类型,
- 函数返回值隐式转换为另一个类型
3. 总结一:
unsigned short Add(unsigned short a, unsigned short b)
{
return a + b;
}
// a被push到寄存器,寄存器位宽32,a和b被默认提升到32int类型 ---- 整数提升:原因是操作数会进入寄存器,int会提升到uint
// 返回类型若是unsigned short,会进行隐式转换,将uint截断到ushort。---- 隐式转换
unsigned int Add2(unsigned short a, unsigned short b)
{
return a + b;
}
// a + b 还是u32类型,不会做整数提升
unsigned long Add3(unsigned int a, unsigned int b)
{
return a + b;
//return static_cast<unsigned long>(a) + b;
}
unsigned long long Add4(unsigned int a, unsigned int b)
{
return a + b;
}
unsigned long long Add5(unsigned int a, unsigned int b)
{
return static_cast<unsigned long long>(a) + b;
}
int main()
{
cout << Add(UINT16_MAX, UINT16_MAX) << endl; // 隐式转换 被截断
cout << Add2(UINT16_MAX, UINT16_MAX) << endl; // 整数提升 正确输出
cout << Add3(UINT32_MAX, UINT32_MAX) << endl; // 32位系统 long 和 int 都是32位 不论是否强转为long 都不会做整数提升
cout << Add4(UINT32_MAX, UINT32_MAX) << endl; // 32位系统 尽管返回值类型为 long long ,不会进行整数提升
cout << Add5(UINT32_MAX, UINT32_MAX) << endl; // 显示强转其中一个参数,另一个参数会进行 整数提升,正确输出
cout << sizeof(long long) << endl;
return 0;
}
结果:
65534 ->1111 1111 1111 1110 被截断 只取低16位bit
131070 -> 0001 1111 1111 1111 1110 完整答案
4294967294 -> 1111 1111 1111 1111 1111 1111 1111 1110 溢出导致最后 1 bit为0 (记住无符号数:1 + 1 = 0)
4294967294 -> 1111 1111 1111 1111 1111 1111 1111 1110 溢出导致最后 1 bit为0 (记住无符号数:1 + 1 = 0)
8589934590
8
4. 有符号数 溢出 – 影响符号位
若算术运算的计算结果太大而无法在系统位宽范围内存储时导致整数溢出
int8: -128 - 1 = 127
二进制:1000 0000 - 1 = 0111 1111
int8:127 + 1 = -128
二进制:01111111 + 1 = 1000 0000
5. 无符号数 反转(回绕) – 最高位进退位失效
无符号操作数的计算不会溢出,因为结果不能被无符号类型表示的时候,就会对比结果类型能表示的最大值加1再执行求模操作。
uint8:255 + 1 = 0
二进制: 1111 1111 + 1 = 0000 0000
总结二
确保无符号整数运算时不会出现反转
确保有符号整数运算时不会出现溢出
确保整型转换时不会出现截断错误
确保有符号和无符号数之间的转换符合预期
把整型表达式比较或赋值为一种更大类型之前必须用这种更大类型对他进行求值
避免对有符号整数进行位操作符运算