数据类型转换中存在的问题分析
隐式类型转换(implicit type conversion)
隐式类型转换(implicit type conversion)包括整型提升(integer promotion)和标准算数转换(usual arithmetic conversions)
遵循较大范围优先规则
1. 整型提升(integer promotion)
C语言规定,表达式中各种小于int长度的整型值(signed/unsigned character/short integer),都必须先转换为int或unsigned int,才能送入CPU取执行运算。因为CPU中的整型运算器(ALU)操作数长度是int字节长度,使用的通用寄存器长度也是。
验证
#include <stdio.h>int main(int argc, char const *argv[])
{char a = 0xb6;short b = 0xb600;int c = 0xb6000000;if (a == 0xb6)printf("a");if (b == 0xb600)printf("b");if (c == 0xb6000000)printf("c");/*最后输出结果为c因为整型提升:a/b整型提升为int类型*/return 0;
}
#include <stdio.h>int main(int argc, char const *argv[])
{char a = 1;printf("%u", sizeof(a));printf("\n");printf("%u", sizeof(+a)); // 单操作符+,一个主要作用就是“整型提升”/*输出:14*/return 0;
}
2. 标准算数转换(usual arithmetic conversions)
当两个不同的类型操作数进行算数运算时,它们会先转换为一种类型,然后进行计算。转换规则通常是**“较大范围”的类型优先**
#include <stdio.h>int main(int argc, char const *argv[])
{int a = -5;unsigned int b = 10;int result = a + b; // a会被转成无符号整数,最终的运算会按照无符号整数的规则进行printf("result: %d\n", result); // 5return 0;
}
这里为什么输出结果是正确的,原因在于:printf的%d格式符,结果被解释为有符号整数,即 ( 11111111111111111111111111111011 ) 2 + ( 10 ) 10 (1111 1111 1111 1111 1111 1111 1111 1011)_{2}+(10)_{10} (11111111111111111111111111111011)2+(10)10 解释为有符号整数,这个二进制超出unsigned integer表示范围,解释为负数。
-5的原码 | -5的反码 | -5的补码 |
---|---|---|
0x0000 0005 | 0xFFFF FFFA | 0xFFFF FFFB |
实例: 有符号和无符号混合运算问题
当不同数据类型进行运算时,编译器会根据转换规则进行隐式类型转换(如:整数和浮点数运算),以确保所有操作数的类型一致。
问题描述:
这里涉及到的是符号扩展问题,即当进行类型转换或位操作时,编译器将原数据的符号位(最高位)扩展到更高位。
#include <stdio.h>int main()
{int a = -1; // 有符号整数 0xFFFF FFFFunsigned int b = 1; // 无符号整数if (a > b){printf("a > b\n");}else{printf("a <= b\n");}/*输出结果:a > b分析:在a,b进行比较时,a发生了隐式类型转换,转换为unsigned integer-1的计算机表示采用补码(整数采用补码表示):0x1000 0001 // 原码0xFFFF FFFE // 反码0xFFFF FFFF // 补码因此a整型 隐式转换之后的结果为:4,294,967,295*/return 0;
}
解决方案:
#include <stdio.h>int main()
{int a = -1; // 有符号整数 0xFFFF FFFFunsigned int b = 1; // 无符号整数if (a > (int)b) // 解决方案{printf("a > b\n");}else{printf("a <= b\n");}/*输出结果:a > b*/return 0;
}
数据类型范围溢出(overflow)
超出了所使用的数据类型所表示的范围,则会出现溢出现象。
整型溢出
#include <stdio.h>
#include <limits.h>
#include <cmath>int main(int argc, char const *argv[])
{int max_int = INT_MAX;int result = max_int + 2;printf("int max value: %d\n", max_int);printf("result: %d\n", result);/*输出结果:int max value: 2147483647result: -2147483647*/return 0;
}
浮点数溢出
#include <stdio.h>
#include <float.h>
#include <math.h>int main(int argc, char const *argv[])
{float large_float = FLT_MAX;float overflow_result = large_float * 2.0;printf("large_float: %e\n", large_float);printf("overflow result: %e\n", overflow_result);if (overflow_result == INFINITY){printf("result is Infinity\n");}/*输出结果:large_float: 3.402823e+038overflow result: 1.#INF00e+000result is Infinity*/return 0;
}
实例:
#include <stdio.h>int main(int argc, char const *argv[])
{long long_value = 2147483648;int int_value = (int)long_value;printf("%d\n", int_value);return 0;/*输出:-2147483648*/
}
数据截断(data truncation)
数据截断导致精度的损失:当高精度数据类型转成低精度数据类型时,会出现精度损失。例如:小数部分会直接截断
#include <stdio.h>int main(int argc, char const *argv[])
{float hv = 123.456;int lv = (int)hv;printf("%d\n", lv); // 123return 0;
}
reference
C++/C implicit conversion
integer promotion