C中的类型混合整数除法:编译器错误或定义的行为?

Posted

技术标签:

【中文标题】C中的类型混合整数除法:编译器错误或定义的行为?【英文标题】:Type-mixed integer division in C: compiler bug or defined behaviour? 【发布时间】:2017-10-31 12:33:39 【问题描述】:

在为使用 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

这是一个错误,还是只是定义的行为?

【问题讨论】:

【参考方案1】:

在 C 上进行数学运算时,narrower 类型将转换为 wider 类型。在您的情况下,所有int32_t 变量都转换为uint32_t,这是由于促销的影响。

-4000uint32_t 中是一个很大的数字。事实上,它是0xFFFFFFFF - 4000,大约是 40 亿。如果你将 40 亿(或其他)除以 4,就会得到你所拥有的结果。

通过在任何地方使用相同的类型或在使用变量之前进行强制转换来解决您的问题:

volatile int32_t z = x / (int32_t)y;

打印结果时,%d 使用 int32_tuint32_t 是未定义的行为,因为它仅适用于 int 类型。

【讨论】:

谢谢你的解释,有道理。 re: printf,我相信编译器会将所有可变整数类型都转换为 int 类型,因此使用 uint32_t 和朋友 应该 工作。不过,我有待纠正。 @TomOldbury 你认为错了。 Long 也是 varuadic int 但你必须使用 %l 。

以上是关于C中的类型混合整数除法:编译器错误或定义的行为?的主要内容,如果未能解决你的问题,请参考以下文章

C整数除法和下限

bigdecimal类型除法问题

linux 除法保留小数

mysql 里面用啥数据类型来定义手机号码?

《代码大全》阅读笔记-12-基本数据类型

C中如何定义decimal类型