我在 C 中遇到了这段代码:
*p++=*q++=*r++;
在我看来这是错误的,因为我无法回想起C中的任何规则,指明q之后的++
应该在*p++
和*q++
之间的分配之前实际进行,或者后?
因此,我的印象是,这很可能是未定义的行为,但无法确定 C 标准中的确切位置( C89或C99 )这是占了。
这是语言警察的帮助非常感谢。请轻松一点。
答案 0 :(得分:3)
此代码的行为完全不依赖于物理执行++
的时间。行为定义明确。
使用 postfix 形式的增量这一事实只是意味着指针的原始值被用作增量的结果。即整件事情相当于
old_p = p;
old_q = q;
old_r = r;
*old_p = *old_q = *old_r;
p = p + 1;
q = q + 1;
r = r + 1;
请注意,您可以以完全任意的方式自由移动物理增量,如
old_p = p;
old_q = q;
old_r = r;
p = p + 1;
q = q + 1;
*old_p = *old_q = *old_r;
r = r + 1;
只要在赋值中使用原始指针值,代码的语义就不会改变。
另请注意,原始值必须存储才能在分配中使用。编译器可以通过递减重新评估来恢复原始值。即编译器甚至可以将表达式转换为类似
的表达式p = p + 1;
q = q + 1;
*(p - 1) = *(q - 1) = *r;
r = r + 1;
答案 1 :(得分:2)
由于您正在递增三个不同的指针变量,因此整体行为得到了很好的定义(假设指针都指向有效的存储位置)。未指定r
的增量是在分配到p
之前还是之后发生,但这也不会影响结果。
为方便起见,假设我们有:
char buffer1[10];
char buffer2[10];
char buffer3[] = "abc";
char *p = buffer1;
char *q = buffer2;
char *r = buffer3;
*p++ = *q++ = *r++;
执行此操作后,所有这些断言都是安全的:
assert(p == buffer1 + 1); // Or p == &buffer1[1];
assert(q == buffer2 + 1); // Or q == &buffer2[1];
assert(r == buffer3 + 1); // Or r == &buffer3[1];
assert(*r == 'b');
assert(buffer1[0] == 'a');
assert(buffer2[0] == 'a');
答案 2 :(得分:1)
作业lower precedence比*
和++
(发布和发布)都要{{3>},因此作业将在之后发生,但操作数的评估顺序为=
未指定,在这种情况下无关紧要,除非r
,p
或q
指向同一位置,无论如何您都会undefined behavior您将在同一序列点内多次修改同一个对象。
C99标准草案部分6.5.16
分配运营商段 3 说:
[...]更新左操作数的存储值的副作用 发生在前一个和下一个序列点之间。[...]
和段 4 说:
未指定操作数的评估顺序。 [...]
答案 3 :(得分:0)
如果我没有弄错的话,总是在作业结束时执行后递增
即
* r
增量* Q< - * R
* q
增量* p< - * q
* p
中的增量