Using designated initializers with unnamed nested data types

戏子无情 提交于 2019-12-11 04:23:12

问题


I'm wondering if it is possible to use designated initializers in unnamed data members of structs... (Yikes, a mouthful, but yes, it is the cleanest way to do what I'm trying to do...). If I have:

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 };

and I try to compile, I get the error:

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

I've also tried using .main..a64, but I'm getting other issues. This is with gcc 4.4. Unfortunately, the MainStruct is used all over the code, so naming the union would involve changing hundreds of files, so I'd like to avoid that. I'd also like to avoid any assumptions about position of MainStruct within OtherStruct if possible.


回答1:


You need to change the syntax a bit, initializing .main within the initializer for 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 };

Here is a working test program:

#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);

}

Compiled with gcc -std=c11 -Wall -Wextra -Wpedantic, here is the program output:

5, 10
3

Update

This use of designated initializers should also work with at least C99, though C99 does not support unnamed structures or unions. Here is an example:

#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;
}

Compiled with gcc -std=c99 -Wall -Wextra -Wpedantic, here is the program output:

instance id: first
instance state.x = 5
instance state.arr[0] = 1
instance state.arr[1] = 2

Final Note

It turns out that OP's original syntax of:

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

should also work on both C99 and C11, but is not supported in older standards which do not allow initialization of subobjects.

Unnamed unions are not supported in C99, but are available as a GNU extension. Further investigation has turned up this bug report which suggests that designated initializers for unnamed structs and unions were fixed in gcc 4.6. As workaround, it was suggested at this link to enclose the offending initializer in braces; it is also mentioned that this workaround is a bit finicky and position dependent, which may explain why it does not work here for OP.



来源:https://stackoverflow.com/questions/43102901/using-designated-initializers-with-unnamed-nested-data-types

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!