gpt4 book ai didi

c - gcc 在某些数组前/后增量情况下的奇怪行为(已编辑)

转载 作者:太空狗 更新时间:2023-10-29 15:22:01 25 4
gpt4 key购买 nike

我正在编写一个编译器,它在 {} 范围内大体上符合 C99 的语义。当试图对 gcc 如何处理某些“未定义的行为”进行逆向工程时,具体地说,变量的链式前后增量,我注意到如果将其与修改赋值(例如“*=”)和数组访问。简化到最简单的明显困惑点,gcc 4.6.3。评估(有和没有选项 -std=c99):

a[0] = 2;
a[0] *= a[0]++;

a[0] = 3.

我是不是记错了标准? 任何是否已经未定义前增量或后增量的使用,而不仅仅是复合表达式中的链接使用?

此外,即使行为是“未定义的”,上面的计算结果的方法似乎特别糟糕,因为我只能看到你如何证明结果为 5(= 2*2 + 1,我会实现 - 在赋值语句后后递增)或 6(= 3 * 2,使用一个变量,然后立即对其进行后递增,并按解析顺序处理 - 解析器几乎肯定会评估“* ="在评估 RHS 表达式之后)。从 C 或 C++ 的角度对此有何见解?

我在尝试将数组与具有前后增量的整数表达式边界结合起来时注意到了这一点,并意识到这真的很难;但是,考虑到 gcc 的旗舰地位,以上内容似乎有点像逃避。

这是在 Ubuntu 12.04 下。

编辑:我应该补充说,如果变量不是数组元素,则可以对 gcc 的行为进行逆向工程 - 至少我尝试的所有示例都按如下方式工作:(1) 计算所有复合表达式预增量; (2) 计算表达式; (3) 评估所有复合表达式后增量。所以这可能也与上面的“真的很难”有关。

注意:clang 产生哲学上合理的值 6。我用 clang 运行了更详细的案例,并且有理由确定它对数组访问和标量情况的处理相同,并且按照我上面描述的哲学上的第二个进行操作合理的方式。

最佳答案

赋值中的突变(包括读取和突变赋值,例如 *=)和后增量中的突变可以在初始访问值后的表达式求值中的任何时间发生的突变细胞。因此,*=a[0]++ 中的 a[0] 的突变彼此没有顺序。显然在这种情况下,gcc 选择从左到右执行它们。

或者更准确地说,表达式:

x *= y++;

可以重写为:

tmp1 = y + 1;        tmp2 = x * y;
x = tmp1; y = tmp2;

其中列可以按任何顺序交错。

请注意,在实践中,两个 tmp 变量都可能是机器寄存器。事实上,可能发生的事情更像这样:

r1  = y;
r2 = r1 + 1;
r3 = x;
r4 = r3 * r1;
x = r4;
y = r2;

那么为什么最后两个作业按那个顺序而不是另一个顺序呢?好吧,为什么不呢?

显然,这里的混淆是 xy 是相同的位置,但 gcc 没有义务注意到这一点。它可能使用基于它们位于不同位置的假设的优化启发式。

但假设它确实注意到它们是相同的。在这种情况下,可以取消一项或多项分配。而且,还可以省去要存储的临时文件的计算。所以编译器可以选择删除 r4 = r3 * r1; x = r4r2 = r1 + 1; y = r2。在选择消除增量或乘法时,自尊的优化器会做什么?

关于c - gcc 在某些数组前/后增量情况下的奇怪行为(已编辑),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23936861/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com