这个问题在这里已经有了答案:
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/