c - 深奥的 C 指定初始化程序失败,编译器错误或功能?

标签 c struct initialization designated-initializer

直到凌晨 1 点左右,我一直在追踪我代码中的一个错误,结果让我大吃一惊。实际代码非常复杂,涉及包含结构 union 的结构 union 等。但我已将问题提炼为以下简化的失败案例。

发生的事情是编译器 [gcc 5.4.0] 正在更改指定初始化程序的执行顺序以匹配它们在结构中出现的顺序。只要您使用没有顺序依赖性的常量或变量初始化结构,这就不会导致任何问题。查看以下代码。它表明编译器清楚地重新排序了指定的初始化程序:

#include <stdio.h>

typedef const struct {
    const size_t First_setToOne;
    const size_t Second_setToThree;
    const size_t Third_setToTwo;
    const size_t Fourth_setToFour;
} MyConstStruct;

static void Broken(void)
{
    size_t i = 0;

    const MyConstStruct myConstStruct = {
        .First_setToOne     = ++i,
        .Third_setToTwo     = ++i,
        .Second_setToThree  = ++i,
        .Fourth_setToFour   = ++i,
    };

    printf("\nBroken:\n");
    printf("First_setToOne    should be 1, is %zd\n", myConstStruct.First_setToOne   );
    printf("Second_setToThree should be 3, is %zd\n", myConstStruct.Second_setToThree);
    printf("Third_setToTwo    should be 2, is %zd\n", myConstStruct.Third_setToTwo   );
    printf("Fourth_setToFour  should be 4, is %zd\n", myConstStruct.Fourth_setToFour );
}

static void Fixed(void)
{
    size_t i = 0;

    const size_t First_setToOne     = ++i;
    const size_t Third_setToTwo     = ++i;
    const size_t Second_setToThree  = ++i;
    const size_t Fourth_setToFour   = ++i;

    const MyConstStruct myConstStruct = {
        .First_setToOne     = First_setToOne   ,
        .Third_setToTwo     = Third_setToTwo   ,
        .Second_setToThree  = Second_setToThree,
        .Fourth_setToFour   = Fourth_setToFour ,
    };

    printf("\nFixed:\n");
    printf("First_setToOne    should be 1, is %zd\n", myConstStruct.First_setToOne   );
    printf("Second_setToThree should be 3, is %zd\n", myConstStruct.Second_setToThree);
    printf("Third_setToTwo    should be 2, is %zd\n", myConstStruct.Third_setToTwo   );
    printf("Fourth_setToFour  should be 4, is %zd\n", myConstStruct.Fourth_setToFour );
}

int main (int argc, char *argv[])
{
    (void)argc;
    (void)argv;

    Broken();
    Fixed();

    return(0);
}

输出如下:

Broken:
First_setToOne    should be 1, is 1
Second_setToThree should be 3, is 2
Third_setToTwo    should be 2, is 3
Fourth_setToFour  should be 4, is 4

Fixed:
First_setToOne    should be 1, is 1
Second_setToThree should be 3, is 3
Third_setToTwo    should be 2, is 2
Fourth_setToFour  should be 4, is 4

我怀疑优化器,但我尝试了使用每个可能的优化级别的相同代码,但重新排序仍然发生。所以这个问题在基础编译器中。

我有一个解决方案,所以这更像是对其他人的警告和一个一般性问题。

有没有其他人看到或注意到这个问题?

这是预期/指定的行为吗?

最佳答案

C99 标准允许以任何顺序应用副作用:

6.7.8.23: The order in which any side effects occur among the initialization list expressions is unspecified.

脚注提供了进一步的说明:

In particular, the evaluation order need not be the same as the order of subobject initialization.

关于c - 深奥的 C 指定初始化程序失败,编译器错误或功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48288853/

相关文章:

initialization - 在启动时执行 Fortran 代码?

c++ - 有没有办法在 C++ 编译器中禁用复制省略

c - 什么是 __lll_lock_wait_private 和 __lll_lock_wait_private,为什么它们会减慢我的代码速度?

c - 运行此代码时显示段错误错误

json - 编码类型时如何将方法结果嵌入到 JSON 输出中?

Beego Controller 中的 JSON 响应

swift - 带有@escaping 参数的类初始化器

c - 如何使用指针?在C中

c - 简化逻辑表达式

c++ - Swift、C++ 和结构