4

我有小 C 代码:

#include<stdio.h>
int main() 
{
    int  z[]= {1,2,3,4,5,6};
    int i = 2, j;
    printf("i=%d  \n",i); 

    z[i] = i++;

    for (j=0;j < 6;j++ )
       printf ("%d ", z[j]);

    printf("\ni=%d \n",i); 
}

输出:

i=2  
1 2 2 4 5 6 
i=3

计算表达式的优先顺序是首先,计算 z[i]。因为 i 在这里是 2,所以它变成 z[2]。接下来,计算 i++,即产生 2,i 变为 3。最后,执行 =,并将 2(即从 i++ 产生的值)放入 z[2]

这解释了上述输出,即 1 2 2 4 5 6

但是如果我们把上面的代码从 i++ 改成 ++i 即

#include<stdio.h>
int main() 
{
    int  z[]= {1,2,3,4,5,6};
    int i = 2, j;
    printf("i=%d  \n",i); 

    z[i] = ++i;

    for (j=0;j < 6;j++ )
       printf ("%d ", z[j]);

    printf("\ni=%d \n",i); 
}

然后输出就奇怪的不同了,那就是:

i=2  
1 2 3 3 5 6 
i=3

如果我们按照上述优先级(C 规范所说的 [index] 早于 ++ 绑定),那么输出应该是 1 2 3 4 5 6。

我只是想知道为什么上面的优先顺序不能解释这一点?

我的编译器是 ubuntu 11.04 上的 gcc 4.5.2

谢谢和问候, 卡皮尔

4

5 回答 5

5

z[i] = ++i;导致未定义的行为:

6.5 表达式
...
2 如果标量对象的副作用相对于同一标量对象的不同副作用或使用相同标量对象的值的值计算是未排序的,则行为未定义。如果一个表达式的子表达式有多个允许的排序,则如果在任何排序中出现这种未排序的副作用,则行为是未定义的。84)
84) 本段呈现未定义的语句表达式,例如

    i = ++i + 1;
    a[i++] = i;
同时允许

    i = i + 1;
    a[i] = i;

请注意,优先级仅控制运算符和操作数的分组;它控制评估的顺序。

运算符 in的副作用相对于运算符++in++i无序的;编译器不需要以任何特定顺序评估这两个表达式。另请注意,在计算表达式后不需要立即应用的副作用;它只需要在下一个序列点之前应用。 []z[i]++i

于 2013-05-15T10:24:53.920 回答
3

这不是错误,请查看GCC 非错误部分。这种测试会导致不可预知的结果,他们知道这一点。

在两个序列点之间修改一个值两次 [...] 会导致未定义的行为。

于 2013-05-15T10:22:02.010 回答
2
 z[i] = ++i;

是未定义的行为

引用cppreference.com 的 C 部分

1) 如果标量对象上的副作用相对于同一标量对象上的另一个副作用是未排序的,则行为未定义。

我=++我+我++;// 未定义的行为

于 2013-05-15T10:32:46.940 回答
0

z[i] = ++i;

调用未定义的行为。

于 2013-05-15T10:19:22.130 回答
0

http://www.faqs.org/faqs/C-faq/faq/问题 3.1 至 3.9。这些几乎是所有与您的问题相似的问题的答案。

但简而言之,两个序列点之间的评估顺序(这些由 C 标准 - C99 附录 C 明确定义)是未定义的行为。

在两个序列点之间,一个对象被修改了不止一次,或者被修改并读取了先前的值而不是确定要存储的值

于 2013-05-15T10:35:44.663 回答