具有后增量的连续指针赋值

时间:2013-11-22 03:08:00

标签: c undefined-behavior

我在 C 中遇到了这段代码:

*p++=*q++=*r++;

在我看来这是错误的,因为我无法回想起C中的任何规则,指明q之后的++应该在*p++*q++之间的分配之前实际进行,或者后?

因此,我的印象是,这很可能是未定义的行为,但无法确定 C 标准中的确切位置( C89或C99 )这是占了。

这是语言警察的帮助非常感谢。请轻松一点。

4 个答案:

答案 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>},因此作业将在之后发生,但操作数的评估顺序为=未指定,在这种情况下无关紧要,除非rpq指向同一位置,无论如何您都会undefined behavior您将在同一序列点内多次修改同一个对象。

C99标准草案部分6.5.16 分配运营商 3 说:

  

[...]更新左操作数的存储值的副作用   发生在前一个和下一个序列点之间。[...]

和段 4 说:

  

未指定操作数的评估顺序。 [...]

答案 3 :(得分:0)

如果我没有弄错的话,总是在作业结束时执行后递增

  

* r

增量      

* Q< - * R

     

* q

增量      

* p< - * q

     

* p

中的增量

It is important to note that a postfix increment or decrement expression evaluates to the value of the expression prior to application of the respective operator.