C 中的类型混合整数除法:编译器错误或定义的行为?
Type-mixed integer division in C: compiler bug or defined behaviour?
我在为使用 GCC 编译的小型 ARM 处理器编写软件时遇到了一个怪癖。该处理器没有硬件除法引擎,所以除法是在软件中实现的。
以下代码复制了行为,volatile 语句用于避免优化:
volatile int32_t x = -4000;
volatile uint32_t y = 4;
volatile int32_t z = x / y;
uart_printf(DBG_LVL_INFO, "%d / %d = %d\r\n", x, y, z);
z 的打印结果是 1073740824
,但我希望结果是 -1000
。
类型混合似乎很关键。将 uint32_t
替换为 int32_t
可解决错误。
-1000
被错误地解释为无符号整数不会产生结果,有趣的是,结果似乎等于结果加上 230.
这是一个错误,还是只是定义的行为?
在 C 上进行数学运算时,narrower 类型将转换为 wider 类型。在你的例子中,所有 int32_t
变量都转换为 uint32_t
,这是由于 promotion 的影响。
-4000
在uint32_t
中是一个很大的数字。事实上,它是 0xFFFFFFFF - 4000
,大约是 40 亿。如果将 40 亿(和一些东西)除以 4,就会得到结果。
通过在所有地方使用相同的类型或在使用变量之前进行强制转换来解决您的问题:
volatile int32_t z = x / (int32_t)y;
打印结果时,使用 int32_t
或 uint32_t
%d
是未定义的行为,因为它仅适用于 int
类型。
我在为使用 GCC 编译的小型 ARM 处理器编写软件时遇到了一个怪癖。该处理器没有硬件除法引擎,所以除法是在软件中实现的。
以下代码复制了行为,volatile 语句用于避免优化:
volatile int32_t x = -4000;
volatile uint32_t y = 4;
volatile int32_t z = x / y;
uart_printf(DBG_LVL_INFO, "%d / %d = %d\r\n", x, y, z);
z 的打印结果是 1073740824
,但我希望结果是 -1000
。
类型混合似乎很关键。将 uint32_t
替换为 int32_t
可解决错误。
-1000
被错误地解释为无符号整数不会产生结果,有趣的是,结果似乎等于结果加上 230.
这是一个错误,还是只是定义的行为?
在 C 上进行数学运算时,narrower 类型将转换为 wider 类型。在你的例子中,所有 int32_t
变量都转换为 uint32_t
,这是由于 promotion 的影响。
-4000
在uint32_t
中是一个很大的数字。事实上,它是 0xFFFFFFFF - 4000
,大约是 40 亿。如果将 40 亿(和一些东西)除以 4,就会得到结果。
通过在所有地方使用相同的类型或在使用变量之前进行强制转换来解决您的问题:
volatile int32_t z = x / (int32_t)y;
打印结果时,使用 int32_t
或 uint32_t
%d
是未定义的行为,因为它仅适用于 int
类型。