当前位置: 首页 > 知识库问答 >
问题:

在循环中的哪个点,整数溢出会变成未定义的行为?

籍昱
2023-03-14

这是一个例子来说明我的问题,其中涉及一些更复杂的代码,我不能在这里张贴。

#include <stdio.h>
int main()
{
    int a = 0;
    for (int i = 0; i < 3; i++)
    {
        printf("Hello\n");
        a = a + 1000000000;
    }
}

这个程序在我的平台上包含未定义的行为,因为a会在第三个循环上溢出。

这会使整个程序有未定义的行为,还是只有在溢出真正发生之后?编译器可能会发现a会溢出,这样它就可以声明整个循环未定义,并且不用费心运行printfs,即使它们都发生在溢出之前?

(标记的C和C虽然不同,但我对这两种语言的答案感兴趣,如果它们不同的话。)

共有3个答案

柯建业
2023-03-14

针对16位int的积极优化C或C编译器会知道将1000000000添加int类型的行为是未定义的。

任何一个标准都允许它做任何它想要的事情,其中可能包括删除整个程序,留下int main(){}

但是更大的整数呢?我还不知道有哪个编译器能做到这一点(而且我无论如何都不是C和C编译器设计方面的专家),但我想有时候,一个以32位int或更高位int为目标的编译器会发现循环是无限的(我不会改变),所以最终会溢出。因此,它可以再次将输出优化为int main(){}。我在这里想说的是,随着编译器优化变得越来越激进,越来越多的未定义行为结构正在以意想不到的方式表现出来。

您的循环是无限的这一事实本身并不是未定义的,因为您正在写入循环主体中的标准输出。

丌官绍元
2023-03-14

首先,让我纠正这个问题的标题:

未定义的行为(具体而言)不是执行领域。

未定义的行为会影响所有步骤:编译、链接、加载和执行。

要巩固这一点,请记住没有一节是详尽的:

  • 编译器可以假设包含Undefined Behavior的代码部分永远不会执行,因此假设导致这些行为的执行路径是死代码。看看除了Chris Lattner,每个C程序员都应该知道什么是未定义的行为
  • 链接器可以假设在弱符号(通过名称识别)的多个定义存在的情况下,由于“一个定义规则”,所有定义都是相同的
  • 加载器(如果您使用动态库)可以假设相同,从而选择它找到的第一个符号;这通常用于在Unix上使用LD_PRELOAD技巧拦截调用
  • 如果使用悬空指针,执行可能会失败(SIGSEV)

这就是未定义行为的可怕之处:几乎不可能提前预测将发生的确切行为,并且必须在每次更新工具链,底层操作系统时重新进行这种预测...

我建议看迈克尔·斯宾塞(LLVM开发者)的视频:2016年CppCon:我的小优化器:未定义的行为是魔法。

田兴怀
2023-03-14

如果您对纯理论答案感兴趣,C标准允许未定义的行为“时间旅行”:

[执行简介]/5:执行格式良好的程序的一致性实现应产生与具有相同程序和相同输入的抽象机器相应实例的可能执行之一相同的可观察行为。但是,如果任何此类执行包含未定义的操作,则本标准对使用该输入执行该程序的实现没有要求(甚至对第一个未定义操作之前的操作也没有要求)

因此,如果您的程序包含未定义的行为,那么整个程序的行为就是未定义的。

 类似资料:
  • C99标准中哪里说有符号整数溢出是未定义的行为? 我看到关于无符号整数溢出的评论定义得很好(看看为什么定义了无符号整数溢出行为,但没有定义有符号整数溢出?)在第6.2.5节中: 涉及无符号操作数的计算永远不会溢出,因为不能由结果无符号整数类型表示的结果将被减少为比结果类型可以表示的最大值大一的数的模。 但是我在附录J中查看了未定义的行为,我只在列表中看到了这些类似的项目: 具有有符号提升类型的表达

  • 众所周知,有符号整数溢出是一种未定义的行为。但是在C 11文档中有一些有趣的东西: 带符号整数类型,宽度分别为8、16、32和64位,不带填充位,并使用2的补码表示负值(仅在实现直接支持该类型时提供) 参见链接 我的问题是:既然标准明确规定,、、和负数是2的补码,那么这些类型的溢出仍然是一种未定义的行为吗? 编辑我检查了C 11和C11标准,以下是我的发现: C 11,§18.4.1: 标题定义了

  • 我是codeigniter的初学者,我正在制作一个用于学习的基本积垢。我在索引中遇到了一个错误。php 遇到PHP错误严重性:注意:消息:未定义变量:posts 文件名:posts/index。php 行号:2 回溯: 文件:/opt/lampp/htdocs/codeigniter/application/views/posts/index。php 行:2 函数:\u错误\u处理程序 文件:/o

  • 假设我有以下 C 代码: 当< code>x == INT_MAX时,这是未定义的行为。现在假设我用内联汇编执行了加法: 问题:当< code>x == INT_MAX时,内联汇编版本是否仍然调用未定义的行为?还是未定义的行为只适用于C代码?

  • 未定义行为的一个例子是在flow上的整数行为 有没有一个历史的或者(甚至更好!)造成这种差异的技术原因是什么?

  • 问题内容: 我被困在我应该声明一个称为“ phrase”的字符串变量的部分,该变量不应一直循环播放。 让您知道我的任务是:与选项1相似,不同之处在于用户在输入第一队的结果后输入“ N”(而不是“ Q”)。然后,程序输入第二个团队名称及其结果,直到输入“ Q”。输出两个语句,例如选项1中的语句,然后输出第三条语句,该语句说明哪个团队处于第一位(基于点数) 输入样例: 样本输出: 更新 : 我的代码: