INT_MIN % -1 是否会产生未定义的行为?

发布于 2024-11-05 09:28:19 字数 229 浏览 5 评论 0原文

gcc 生成浮动代码,为以下代码引发 SIGFPE

#include <limits.h>
int x = -1;
int main()
{
    return INT_MIN % x;
}

但是,我在标准中找不到该代码调用未定义或实现定义的行为的声明。据我所知,它需要返回 0。这是 gcc 中的错误还是我错过了标准的一些特殊异常?

gcc generates floating code that raises SIGFPE for the following code:

#include <limits.h>
int x = -1;
int main()
{
    return INT_MIN % x;
}

However I can find no statement in the standard that this code invokes undefined or implementation-defined behavior. As far as I can tell, it's required to return 0. Is this a bug in gcc or am I missing some special exception the standard makes?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

木槿暧夏七纪年 2024-11-12 09:28:19

您可能是对的,这可以被视为实际标准中的错误。 当前草案解决了这个问题:

如果商 a/b 可表示,
表达式 (a/b)*b + a%b 应
等于a;否则,行为
a/b 和 a%b 均未定义。

You are probably right that this can be considered as a bug in the actual standard. The current draft addresses this problem:

If the quotient a/b is representable,
the expression (a/b)*b + a%b shall
equal a; otherwise, the behavior of
both a/b and a%b is undefined.

遥远的她 2024-11-12 09:28:19

查看 gcc 生成的汇编代码(x 在汇编中前面定义为 -1):

movl    x, %ecx
movl    $-2147483648, %eax
movl    %eax, %edx
sarl    $31, %edx
idivl   %ecx

第一个计算指令 sarl 右移 -2147483648 31 位。这会导致 -1 被放入 %edx 中。

接下来执行idivl。这是一个签名操作。我引用一下描述:

将组合 %edx:%eax 寄存器中包含的双字内容除以指定的寄存器或内存位置中的值。

所以 -1:-2147483648 / -1 是发生的除法。 -1:-2147483648 解释为双字等于 -2147483648 (在二进制补码机器上)。现在发生 -2147483648 / -1 并返回 2147483648。繁荣!这比 INT_MAX 还多一个。


关于为什么问题,这是 gcc 中的错误还是我错过了标准的一些特殊例外?

在 C99 标准中,这是隐式的 UB (§6.5.5/6):

…/ 运算符的结果是舍去小数部分的代数商。88) 如果商 a/b 可表示,则表达式 (a/b)*b + a%b 应等于 a。

INT_MIN / -1 无法表示,因此这是 UB。

然而,在 C89 中,% 运算符是实现定义的,这是否是编译器错误可以争论。不过,该问题已在 gcc 中列出: http://gcc.gnu.org/bugzilla /show_bug.cgi?id=30484

Looking at the assembly code generated by gcc (x is defined as -1 earlier in the assembly):

movl    x, %ecx
movl    $-2147483648, %eax
movl    %eax, %edx
sarl    $31, %edx
idivl   %ecx

The first computational instruction, sarl, right shifts -2147483648 31 bits. This results in -1 which is put in %edx.

Next idivl is executed. This is a signed operation. Let me quote the description:

Divides the contents of the double-word contained in the combined %edx:%eax registers by the value in the register or memory location specified.

So -1:-2147483648 / -1 is the division that happens. -1:-2147483648 interpreted as a double word equals -2147483648 (on a two's complement machine). Now -2147483648 / -1 happens which returns 2147483648. BOOM! That's one more then INT_MAX.


About the why question, is this a bug in gcc or am I missing some special exception the standard makes?

In the C99 standard this is implicit UB (§6.5.5/6):

…the result of the / operator is the algebraic quotient with any fractional part discarded.88) If the quotient a/b is representable, the expression (a/b)*b + a%b shall equal a.

INT_MIN / -1 cannot be represented, thus this is UB.

In C89 however the % operator is implementation defined and whether this is a compiler bug or not can be debated. The issue is listed at gcc however: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=30484

沩ん囻菔务 2024-11-12 09:28:19

此处作为缺陷报告提出了相同的问题

http:// /www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#614

不幸的是,我没有看到决议部分明确指出它应该产生 UB。除法确实会产生 UB,但对于 % 运算符来说并不明显。

The same question is asked here as a Defect Report

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#614

Unfortunately I don't see it stated explicitly in the resolution part that it should produce UB. The division would indeed produce UB, but for the % operator it is not obvious.

梦里梦着梦中梦 2024-11-12 09:28:19

具有负操作数的模运算的结果在 C89 中由实现定义,并在 C99 中由 §6.5.5/6 定义:

/ 运算符的结果是舍去小数部分的代数商。88) 如果商 a/b 为可表示,表达式 (a/b)*b + a%b 应等于 a

88) 这通常称为“向零截断”。

对于补码表示,INT_MIN / -1 等于 INT_MAX + 1,因此它不能在不换行的情况下表示为 int,并且我猜想实施选择让它具有爆炸性。

The result of the modulus operation with negative operands is left implementation-defined in C89, and defined in C99 by §6.5.5/6:

…the result of the / operator is the algebraic quotient with any fractional part discarded.88) If the quotient a/b is representable, the expression (a/b)*b + a%b shall equal a.

88) This is often called "truncation toward zero".

For a two's-complement representation, INT_MIN / -1 is equal to INT_MAX + 1, so it's not representable as an int without wrapping, and I guess the implementation elects to leave it explosive.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文