关于C语言中long z2 = -z;语句隐式类型转换的技术咨询
解析
long z2 = -z;的隐式类型转换过程 先明确你的代码和输出:
代码
unsigned z = 0x80000000; long z2 = -z; printf("z is %x, z is %u\n", z, z); printf("z2 is %lx, z2 is %ld\n", z2, z2);
运行输出
z is 80000000, z is 2147483648 z2 is 80000000, z2 is 2147483648
下面拆解long z2 = -z;的每一步执行逻辑:
计算
-z的无符号运算规则z是unsigned int类型,值为0x80000000(十进制2147483648)。C语言中,一元负号运算符作用于无符号整数时,不会产生负数,而是遵循无符号数的模运算规则:-z等价于(unsigned int)(0 - z),计算结果按2^N取模(N是该无符号类型的位数,这里是32位)。
具体计算:0 - 0x80000000在32位无符号运算中,结果还是0x80000000(因为模2^32后,负数会被转换为对应的无符号正数)。此时-z的结果仍然是unsigned int类型,值保持0x80000000。无符号数转
long的类型转换
接下来要把unsigned int类型的0x80000000赋值给long类型的z2,这一步的行为取决于你的系统中long的位数:- 64位系统场景:
long是64位带符号整数,取值范围远大于32位无符号数的最大值。此时无符号数转64位带符号数会进行零扩展——高位补0,0x80000000变成64位的0x0000000080000000,这个值作为带符号数就是十进制2147483648,完全在long的合法范围内,所以z2最终的值就是2147483648,和你的输出匹配。 - 32位系统场景:
long是32位带符号整数,最大值是0x7FFFFFFF(2147483647),0x80000000超出了正范围。这种情况属于实现定义行为,大多数系统会直接复制二进制位模式,此时0x80000000对应的32位带符号数是-2147483648,但你的输出显示为正数,说明你的环境是64位系统。
- 64位系统场景:
printf输出的匹配逻辑
用%lx打印z2时,64位的0x0000000080000000会被输出为80000000(前导零自动省略);用%ld打印时,直接输出十进制的2147483648,和你看到的结果完全一致。
内容的提问来源于stack exchange,提问作者Da Wang
相关产品推荐
相关产品推荐

