C++ 中的整数溢出有多灾难性?

发布于 2024-12-28 23:32:21 字数 592 浏览 3 评论 0原文

我只是想知道整数溢出到底有多灾难性。以下面的示例程序为例:

#include <iostream>

int main()
{
    int a = 46341;
    int b = a * a;
    std::cout << "hello world\n";
}

由于 a * a 在 32 位平台上溢出,并且整数溢出会触发未定义的行为,我是否能保证 hello world 实际上会出现在我的屏幕上?


我根据以下标准引用从问题中删除了“签名”部分:

(§5/5 C++03, §5/4 C++11) 如果在计算表达式期间,结果未在数学上定义或不在其类型的可表示值范围内,则行为未定义。

(§3.9.1/4) 无符号整数,声明为unsigned,应遵循算术模 2^n 的法则,其中 n 是该特定大小的值表示中的位数整数。这意味着无符号算术不会溢出,因为无法由生成的无符号整数类型表示的结果会以比生成的无符号整数可以表示的最大值大一的数为模进行缩减类型。

I was just wondering how disastrous integer overflow really is. Take the following example program:

#include <iostream>

int main()
{
    int a = 46341;
    int b = a * a;
    std::cout << "hello world\n";
}

Since a * a overflows on 32 bit platforms, and integer overflow triggers undefined behavior, do I have any guarantees at all that hello world will actually appear on my screen?


I removed the "signed" part from my question based on the following standard quotes:

(§5/5 C++03, §5/4 C++11) If during the evaluation of an expression, the result is not mathematically defined or not in the range of representable values for its type, the behavior is undefined.

(§3.9.1/4) Unsigned integers, declared unsigned, shall obey the laws of arithmetic modulo 2^n where n is the number of bits in the value representation of that particular size of integer. This implies that unsigned arithmetic does not overflow because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting unsigned integer type.

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

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

发布评论

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

评论(3

末骤雨初歇 2025-01-04 23:32:21

正如 @Xeo 在评论中指出的那样(我实际上首先在 C++ 聊天 中提出了它):

未定义的行为确实意味着它,它可能会在您最意想不到的时候袭击您。

最好的例子在这里:为什么使用 GCC 在 x86 上整数溢出会导致无限循环?

在 x86 上,有符号整数溢出只是一个简单的环绕。所以通常情况下,您会期望在 C 或 C++ 中发生同样的事情。但是,编译器可以进行干预,并使用未定义的行为作为优化的机会

在该问题的示例中:

#include <iostream>
using namespace std;

int main(){
    int i = 0x10000000;

    int c = 0;
    do{
        c++;
        i += i;
        cout << i << endl;
    }while (i > 0);

    cout << c << endl;
    return 0;
}

当使用 GCC 编译时,GCC 优化循环测试并使之成为无限循环。

As pointed out by @Xeo in the comments (I actually brought it up in the C++ chat first):

Undefined behavior really means it and it can hit you when you least expect it.

The best example of this is here: Why does integer overflow on x86 with GCC cause an infinite loop?

On x86, signed integer overflow is just a simple wrap-around. So normally, you'd expect the same thing to happen in C or C++. However, the compiler can intervene - and use undefined behavior as an opportunity to optimize.

In the example taken from that question:

#include <iostream>
using namespace std;

int main(){
    int i = 0x10000000;

    int c = 0;
    do{
        c++;
        i += i;
        cout << i << endl;
    }while (i > 0);

    cout << c << endl;
    return 0;
}

When compiled with GCC, GCC optimizes out the loop test and makes this an infinite loop.

幸福不弃 2025-01-04 23:32:21

您可能会触发一些硬件安全功能。所以不,你没有任何保证。

编辑:
请注意,gcc 有 -ftrapv 选项(但它似乎对我不起作用)。

You may trigger some hardware safety feature. So no, you don't have any guarantee.

Edit:
Note that gcc has the -ftrapv option (but it doesn't seem to work for me).

[旋木] 2025-01-04 23:32:21

关于未定义行为有两种观点。有人认为它是为了收集奇怪的硬件和其他特殊情况,但通常它应该表现得正常。有人认为任何事情都有可能发生。根据 UB 的来源,有些人持有不同的观点。

虽然关于溢出的 UB 可能是为了考虑到溢出或饱和的硬件以及表示之间的结果差异而引入的,因此在这种情况下人们可以争论第一种观点,但编写优化器的人非常坚持这样的观点:如果标准不能保证某些事情,那么任何事情都可能发生,他们会尝试使用每一个自由来生成运行速度更快的机器代码,即使结果不再有意义。

因此,当您看到未定义的行为时,请假设任何事情都可能发生,无论给定的行为看起来多么合理。

There are two views about undefined behavior. There is the view it is there to gather for strange hardware and other special cases, but that usually it should behave sanely. And there is the view that anything can happen. And depending on the UB source, some hold different opinions.

While the UB about overflow has probably been introduced for taking into account hardware which trap or saturate on overflow and the difference of result between representation, and so one can argue for the first view in this case, people writing optimizers hold very dearly the view that if the standard doesn't guarantee something, really anything can happen and they try to use every piece of liberty to generate machine code which runs more rapidly, even if the result doesn't make sense anymore.

So when you see an undefined behavior, assume that anything can happen, however reasonable a given behavior may seem.

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