这个问题在这里已经有了答案:




8年前关闭。






正如标准中定义的那样,E1 += E2 几乎与 E1 = E1 + E2 相同,只是 E1 只计算一次。因此,此外,将“p += (*p)++ + c”;导致未定义的行为?

在 gcc/g++ (4.7/4.4) 中尝试以下代码。有两种结果:bxxxxx (g++4.7) 或 axbxxx (gcc, g++ 4.4)。如果我们在代码中执行(1)而不是(2),我们只能得到 axbxxx。

#include <stdio.h>

int main() {
    char s[] = "axxxxx";
    char *p = s;

    printf("s = %s in the beginning.\n"
           "p is pointed at the %d-th char.\n", s, p - s);
    //p = p + (*p)++ * 3 + 2 - 'a' * 3; // (1)
    p += (*p)++ * 3 + 2 - 'a' * 3; // (2)
    printf("p is moved ahead by %d steps\n", p - s);
    printf("s = %s after the operation.\n", s);
    return 0;
}

我找不到它为什么会导致未定义的行为,也不能断言这是 gcc 的错误。

对于 axbxxx 结果,我也无法理解为什么操作数或 post++ 被评估两次(一次获得值,然后保存它)。由于标准中说“1 ...被添加到它”,我认为地址应该只评估一次。如果后++ 的操作数的地址只计算一次,则表达式的效果将是相同的,无论赋值的执行顺序如何。

=== 更新 ===

阅读第一条评论中链接的文档后,我认为以下规则可能很重要:

“2)此外,只能访问先前值以确定要存储的值。” .

那么,在“p = p + (*p)++ * 3 + c”中对 p 的访问是否会被视为 *p 的“先验值”的一部分,它与要存储在 *p 中的值无关?

IMO,这条规则没有被违反。

最佳答案

不, p = p + (*p)++ * 3 + c 不会导致任何未定义的行为,假设 p 不指向 c

在这种情况下,有问题的部分是对表达式中 *p 值的读取和修改。但是,读取该值是为了确定 p 的新值(p 的新值对 *p 中读取的值有直接的数据依赖性),因此它不违反要求。

我猜想编译器中的错误实际上源于其在未指定情况下的错误行为。请注意,该表达式有两个副作用:将新值存储在 p 中,并将新值存储在 *p 中。未指定这些副作用发生的顺序。然而,在 (*p)++ 子表达式的计算过程中,编译器应该“修复” ++ 的特定左值参数,以确保新的(增加的)值存储在那个确切的对象中。看起来旧版本的编译器没有这样做,即首先评估 p 的新值,然后通过 *p 的新值存储 p 的新值。这显然是不正确的。

关于c - "p = p + (*p)++ * 3 + c;"会导致未定义的行为吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12823663/

10-08 21:54