为何uint16_t减法需显式转换?运算结果类型问询
无符号16位整数减法的类型提升问题
问题背景
若所有变量均为uint16_t,为何需对减法结果进行显式强制转换才能得到正确结果?
我使用16位自由运行定时器实现微秒级延时,发现使用16-bit无符号整数时,必须进行显式强制转换,否则while循环会无限执行。但使用uint32_t变量时无此问题。硬件架构为Cortex-M,编译器为GCC 10.3.1
核心问题:当sizeof(操作数) < sizeof(int)时,减法运算的结果是否为int类型?
最小复现测试用例
#include <stdio.h> #include <stdint.h> static void delay_until_not_working(uint16_t start_time, uint16_t delay_time) { uint16_t curr_time = start_time; /* 无限循环——即使是无符号整数 */ while ((curr_time - start_time) < delay_time) { printf("Start: %5d, Curr: %5d, delay: %5d\r\n", (int)start_time, (int)curr_time, (int)delay_time); curr_time++; } } static void delay_until_working(uint16_t start_time, uint16_t delay_time) { uint16_t curr_time = start_time; /* 添加了uint16_t强制转换 */ while ((uint16_t)(curr_time - start_time) < delay_time) { printf("Start: %5d, Curr: %5d, delay: %5d\r\n", (int)start_time, (int)curr_time, (int)delay_time); curr_time++; } } int main() { printf("Delay until working..\r\n"); delay_until_working(65530, 200); printf("Delay until endless loop..\r\n"); delay_until_not_working(65530, 200); return 0; }
问题解答
是的,当操作数的尺寸小于sizeof(int)时,会触发C语言的整数提升规则,减法运算的结果会是int类型,这就是导致循环异常的根本原因:
- 在
delay_until_not_working函数中,curr_time和start_time都是uint16_t,在Cortex-M这类32位系统中,uint16_t的尺寸(2字节)小于int的尺寸(4字节),所以这两个变量会先被提升为int类型再执行减法。 - 当
curr_time从65530递增到65535后,再加1会触发无符号整数溢出,变为0。此时计算curr_time - start_time等价于(int)0 - (int)65530,结果是-65530(一个负的int值)。 - 随后这个负值和被提升为
int的delay_time(200)比较,-65530 < 200永远为真,因此循环陷入无限执行。
而添加显式强制转换后能正常工作的原因:
(uint16_t)(curr_time - start_time)会把提升后的int结果强制转回uint16_t,按照无符号整数的规则,-65530转换后等价于2^16 - 65530 = 6。- 随着
curr_time继续递增,这个差值会从6开始逐步增大,当达到200时,循环条件不满足,正常退出。
关于uint32_t无问题的原因:
在32位系统中,uint32_t的尺寸等于int的尺寸,不会触发向int的整数提升,减法运算结果保持uint32_t类型,溢出后的差值会按无符号整数的模运算规则计算,因此循环能正确判断退出条件。
内容的提问来源于stack exchange,提问作者unalignedmemoryaccess
相关产品推荐
相关产品推荐

