4

好吧,我并不是真的需要这个答案,我只是好奇。

像这样的表达式*ptr++ = a是完全有效的,因为我们正在对两个对象进行操作ptr*ptr但是如果我写*ptr++ = *ptr + a它仍然有效吗?

例如,考虑以下代码段:

int main(void){
   int a[] = {5,7,8,9,2};

   int* p =a;

   *p++ = 76; /*altering the first element */
   *p++ = *p + 32; /*altering the second element */    

   p = a;
   int i;
   for(i = 0;i<5; i++)
      printf("%d ",*p++);

   return 0;
}

我认为表达式没有什么可担心的,*p++ = *p + 32;但我不确定所涉及的序列点。

4

5 回答 5

12

的结果*ptr++ = *ptr + a是未定义的。等号不是序列点,因此ptr在该语句中再次使用的值会导致未定义的行为。只需考虑结果 if ptris 在计算 RHS 表达式之前递增,并将其与在RHS 表达式之后ptr递增的情况进行比较。

注意:这并不是说表达式的结果将来自这两种情况中的任何一种。未定义就是未定义。

基本上,您只能指望两件事:在最后一个序列点和下一个序列点之间的某个时间对后增量进行评估,以及表达式ptr++返回它增加ptr 之前的值。很好*ptr++ = a,因为您可以依靠ptr++.

于 2009-12-02T08:10:12.530 回答
8

首先让我们假设“p”是一个指针类型。
否则所有的操作只是函数调用的语法糖。

让我们把声明分解成几部分。

int* p = a;

*p++ = *p + 32;

<< Sequence Point >>
// Part 1: p++
// Note the definition of post increment in the standard is (5.2.6)
// The result of the expression p++ is the value of 'p' while the value of the 
// objects represented by 'p' is incremented. This can be represented in pseudo code as:
(A) int*  p1 = p;
(B) p = p + 1;

// Part 2: *p (On the result of Part 1) (On *p++)
(C) int& p2 = *p1;  // Note the use of p1;

// Part 3: *p (On *p + 32)
// Note: There is no linkage between this use of 'p' and the 'p' in Part 1&2
(D) int& p3 = *p;

// Part 4: *p + 32;
(E) int p5 = p3 + 32; // Note the use of p3;

// Part 5: Assignment.
(F) p2 = p5;
<< Sequence Point >>

Ordering that must be preserved:
(A) Before (B)
(A) Before (C)
(D) Before (E)
(C) Before (F)
(E) Before (F)

鉴于上述限制:
编译器可以通过多种方式重新排序这些指令,
但要注意的主要一点是,(B)可以发生在任何地方,对(B)的唯一限制是它发生在(A)之后,因此(D) 中定义的 p3 可以是两个不同值之一,具体取决于 (B) 的确切位置。

由于此处无法定义 p3 的值。
结果语句具有未定义的行为。

于 2009-12-02T10:33:55.690 回答
1

就 C 而言,*ptr++ = *ptr + 32根据 6.5.2 将未定义:“如果标量对象的副作用相对于同一标量对象的不同副作用或使用相同标量对象的值的值计算是无序的,则行为未定义。” 您正在修改并尝试ptr在另一个计算中使用 的值,而没有中间的序列点。

于 2009-12-02T14:03:11.680 回答
0

如果你问的是不一样的。它会编译虽然...

这是合法的 - 如果 PTR 指向一个数组,而不是该数组的最后一个单元格,那么递增 PTR 将指向数组中的下一个对象。

*ptr++ = *ptr + 2 等同于 *ptr = *ptr + 2, ptr++

于 2009-12-02T08:03:48.110 回答
0

我认为它是未定义的。不过我不确定。

但是,更广泛的风格点:如果一个表达式让你开始怀疑它是否未定义,也许这表明你的代码不清楚它的意图,需要减少模棱两可,减少不明显的依赖评价顺序。

我曾经认为 C 真的很酷,因为你可以写很多非常简短的语句来做很多疯狂的事情。我不再这么想了。:-)

于 2009-12-02T08:09:46.757 回答