C[i] = A[i++]; 不等于 C[i] = A[i]; 我++; 这里发生了什么?

Amb*_*ant 1 c loops post-increment

我尝试使用循环展开以不同的方式循环遍历数组。

#define MYSIZE 8

int main()
{
    int A[MYSIZE];
    int B[MYSIZE];
    int C[MYSIZE];

    int i = 0;
    while(i < MYSIZE)
    {
        A[i] = i;
        i++;
    }

    /* LOOP 1 */
    i = 0;
    while (i< MYSIZE)
    {
        B[i+0] = A[i+0];
        B[i+1] = A[i+1];
        B[i+2] = A[i+2];
        B[i+3] = A[i+3];
        i += 4;
    }

    /* LOOP 2 */
    i = 0;
    while (i < MYSIZE)
    {
        C[i] = A[i++];
        C[i] = A[i++];
        C[i] = A[i++];
        C[i] = A[i++];
    }

    printf(" i | A | B | C|\r\n");
    i = 0;
    while (i < MYSIZE)
    {
        printf(" %d | %d | %d | %d |\r\n",i,A[i],B[i],C[i]);
        i++;
    }
}
Run Code Online (Sandbox Code Playgroud)

这确实给了我这个结果:

 i | A | B | C |
 0 | 0 | 0 | 1578166688 |
 1 | 1 | 1 | 0 |
 2 | 2 | 2 | 1 |
 3 | 3 | 3 | 2 |
 4 | 4 | 4 | 3 |
 5 | 5 | 5 | 4 |
 6 | 6 | 6 | 5 |
 7 | 7 | 7 | 6 |

Run Code Online (Sandbox Code Playgroud)

我认为 A、B 和 C 应该包含相同的数字。据我了解i++LOOP 2应该与:

/* LOOP 3 */
i = 0
while(i < MYSIZE)
{
    C[i] = A[i];
    i++;
    C[i] = A[i];
    i++;
    C[i] = A[i];
    i++;
    C[i] = A[i];
    i++;
}
Run Code Online (Sandbox Code Playgroud)

事实并非如此。LOOP 3实际上工作正常,但LOOP 2不行。我究竟做错了什么 ?

dbu*_*ush 5

这个表达:

 C[i] = A[i++];
Run Code Online (Sandbox Code Playgroud)

调用未定义的行为,因为在i没有序列点的情况下读取和写入变量。

虽然赋值的右侧必须完全计算才能分配到左侧,但每个子表达式的计算都是无序的,i递增的副作用也是如此。

这在C 标准的第 6.5.16p3 节中关于赋值运算符有详细说明:

赋值运算符在左操作数指定的对象中存储一个值。赋值表达式具有赋值后左操作数的值,但不是左值。赋值表达式的类型是左操作数在左值转换后的类型。更新左操作数的存储值的副作用在左操作数和右操作数的值计算之后排序。操作数的评估是无序的。

在这个特定的例子中,i首先可以读取的值用作 的索引C,然后可以将其作为i++右侧表达式的一部分进行读取和写入。或者,i++可以先求值并递增,然后i可以读取以用作 的索引C

的增量i应该作为单独语句的一部分来完成,以避免这种情况。

C[i] = A[i];
i++;
Run Code Online (Sandbox Code Playgroud)