使用带有未命名嵌套数据类型的指定初始值设定项

时间:2017-03-29 19:52:26

标签: c gcc initialization designated-initializer

我想知道是否可以在未命名的结构数据成员中使用指定的初始值设定项...(哎呀,满口,但是,是的,这是我做的最简洁的方法。做...)。如果我有:

typedef struct MainStruct {
    union {
         uint8_t   a8[16];
         uint64_t  a64[2];
    };
    uint64_t       i64;
} MainStruct_t;

typedef struct OtherStruct {
    MainStruct_t main;
    int          otherval;
} OtherStruct_t;

OtherStruct_t instance = { .main.a64 = { 0, 0 }, .otherval = 3 };

我尝试编译,我收到错误:

tst3.c:16: error: unknown field ‘a64’ specified in initializer

我也尝试使用.main..a64,但我还有其他问题。这是使用gcc 4.4。不幸的是,MainStruct遍及整个代码,因此命名联合将涉及更改数百个文件,所以我想避免这种情况。如果可能的话,我还想避免在MainStruct内对OtherStruct的位置做出任何假设。

1 个答案:

答案 0 :(得分:2)

您需要稍微更改语法,在response的初始值设定项中初始化responseStore

.main

这是一个有效的测试程序:

instance

使用typedef struct MainStruct { union { uint8_t a8[16]; uint64_t a64[2]; }; uint64_t i64; } MainStruct_t; typedef struct OtherStruct { MainStruct_t main; int otherval; } OtherStruct_t; OtherStruct_t instance = { .main = {.a64 = { 0, 0 }}, .otherval = 3 }; 编译,这是程序输出:

#include <stdio.h>
#include <stdint.h>

typedef struct MainStruct {
    union {
         uint8_t   a8[16];
         uint64_t  a64[2];
    };
    uint64_t       i64;
} MainStruct_t;

typedef struct OtherStruct {
    MainStruct_t main;
    int          otherval;
} OtherStruct_t;

OtherStruct_t instance = { .main = {.a64 = { 5, 10 }}, .otherval = 3 };

int main(void)
{
    printf("%d, %d\n", (int) instance.main.a64[0], (int) instance.main.a64[1]);
    printf("%d\n", instance.otherval);

}

更新

这种指定初始化程序的使用也应该至少与C99一起使用,尽管C99不支持未命名的结构或联合。这是一个例子:

gcc -std=c11 -Wall -Wextra -Wpedantic

使用5, 10 3 编译,这是程序输出:

#include <stdio.h>

struct Inner {
    int x;
    int arr[2];
};

struct Outer {
    char id[100];
    struct Inner state;
};

int main(void)
{
    struct Outer instance = { .id = "first",
                              .state = {.x = 5, .arr[0] = 1, .arr[1] = 2 }};

    printf("instance id: %s\n", instance.id);
    printf("instance state.x = %d\n", instance.state.x);
    printf("instance state.arr[0] = %d\n", instance.state.arr[0]);
    printf("instance state.arr[1] = %d\n", instance.state.arr[1]);

    return 0;
}

最后的注释

事实证明OP的原始语法为:

gcc -std=c99 -Wall -Wextra -Wpedantic

也适用于C99和C11,但不允许在不允许初始化子对象的旧标准中使用。

C99不支持未命名的联合,但可以作为GNU扩展名使用。进一步的调查已经出现this bug report,这表明未命名的结构和联合的指定初始化器已在gcc 4.6中修复。作为解决方法,有人建议在此链接中将违规初始化程序括在括号中;还提到这个解决方法有点挑剔和位置依赖,这可以解释为什么它在这里不适用于OP。