C语言常规算术转换疑问:关系与算术运算类型转换问题
C语言常规算术转换的两个常见疑问解答
问题背景
在学习C语言类型转换中的常规算术转换时,原本认为隐式转换是编译器自动将窄类型提升为宽类型,但通过两个实验产生了疑问:
关系运算符实验
#include <stdio.h> int main(void){ unsigned long int a = 8888; unsigned long int c = 0; signed int b = -1; if(a > b){ c = 10; }else { c = 7; } printf("C value is %lu\n",c); }
按数学逻辑,a=8888大于b=-1,c应等于10,但实际运行结果c=7。
算术运算符实验
#include <stdio.h> int main(void){ unsigned long int a = 8888; unsigned long int c; signed int b = -1; c = b + a; printf("C value is %lu\n",c); }
实际运行结果c=8887,而非预期的大数(如4294976184)。
疑问解答
1. 为何关系运算符a > b的结果不符合预期?
这是因为常规算术转换的核心规则:当有符号类型和无符号类型进行比较或运算时,有符号类型会被转换为对应的无符号类型。
在这个例子里:
b是signed int类型的-1,和unsigned long int类型的a比较时,b会被强制转换为unsigned long int类型。- 有符号整数
-1转换为无符号整数时,会按照无符号类型的取值范围做模运算,结果是该无符号类型的最大值(比如64位系统中,unsigned long int的最大值为18446744073709551615)。 - 显然
8888远小于这个最大值,所以a > b的结果为假,执行else分支,c被赋值为7。
2. 算术运算b + a为何得到8887?
同样是常规算术转换规则导致的结果:
- 运算前,
signed int类型的b=-1被转换为unsigned long int类型,值为该类型的最大值(记为ULONG_MAX)。 - 执行加法
ULONG_MAX + 8888时,会发生无符号整数溢出。无符号整数的溢出是标准定义的合法行为,结果为(ULONG_MAX + 8888) % 2^N(N是unsigned long int的位数,比如64位)。 - 因为
ULONG_MAX = 2^N - 1,所以(2^N -1) + 8888 = 2^N + 8887,模2^N后结果就是8887,和实际运行结果一致。这不是异常溢出,而是无符号整数运算的既定规则。
内容的提问来源于stack exchange,提问作者Vignesh
相关产品推荐
相关产品推荐

