将最高位赋值为1时uint32_t出现负值的问题咨询
问题原因分析
1. 格式化输出使用了错误的格式符
printf的%d格式化符仅用于输出signed int类型的值,你输出uint32_t类型的变量时,应该使用<inttypes.h>头文件中定义的PRIu32宏,用法为printf("reg1U= %" PRIu32 "\n", reg1U);。
你当前使用%d输出uint32_t属于未定义行为,在你使用的32位int系统中,unsigned int的传参与signed int兼容,所以程序会把uint32_t的二进制补码按signed int规则解析,最高位为1时就会被识别为负数。
2. 整数提升规则导致不同位宽无符号数表现不同
C语言的默认整数提升规则规定:在表达式运算、可变参数传递等场景中,位宽小于int的整数类型,会先被提升为int类型(如果int可以容纳该类型的所有取值),否则提升为unsigned int类型。
- 对于8位
uint8_t、16位uint16_t,在32位int系统中,它们的所有取值都可以被signed int完整容纳,所以会被提升为signed int,用%d输出会得到正确的正数值,不会出现负数现象。 - 对于32位
uint32_t,它的最大取值为4294967295,超过了32位signed int的最大值2147483647,所以无法被提升为signed int,只能提升为unsigned int,用%d输出就会出现你看到的负数现象。64位uint64_t同理,甚至会因为位宽不匹配出现更严重的输出异常。
3. 比较运算结果是正常的
你代码中的test2 = (reg1U < reg2U ? 1:0)结果为0是完全正确的无符号比较结果:0xfffffff4作为uint32_t的数值是4294967284,0xfffffff2的数值是4294967282,显然前者大于后者,所以比较结果为假,test2赋值为0,不存在运算异常。
修正后的代码示例
#include <stdio.h> #include <inttypes.h> int main() { int reg1S = 0xfffffff4; int reg2S = 0xfffffff2; uint32_t reg1U = 0xfffffff4; uint32_t reg2U = 0xfffffff2; uint8_t test1,test2; test1 = (reg1S < reg2S ? 1:0); test2 = (reg1U < reg2U ? 1:0); printf("signed = %d \t",test1); printf("unsigned = %d \n", test2); printf("reg1S= %d \t", reg1S); printf("reg1U= %" PRIu32 " \n", reg1U); printf("reg2S= %d \t", reg2S); printf("reg2U= %" PRIu32 " \n", reg2U); return 0; }
修正后输出示例:
signed = 0 unsigned = 0 reg1S= -12 reg1U= 4294967284 reg2S= -14 reg2U= 4294967282
内容的提问来源于stack exchange,提问作者Magnus Mikkelsen
相关产品推荐
相关产品推荐

