开发者

Is it possible to "embed" a structure of variable type into another structure? (GCC)

开发者 https://www.devze.com 2023-01-07 23:15 出处:网络
Is it possible to embed a structure of varying type inside another structure in C? Basically I want to do something like this.

Is it possible to embed a structure of varying type inside another structure in C?

Basically I want to do something like this.

struct A { int n; void *config; }

struct AConfig { int a; char *b; }
struct BConfig { int a; float b; }

const struct A table[] = {
    { 103, (void*)(struct AConfig){ 1932, "hello" } },
    { 438, (void*)(struct BConfig){ 14829, 33.4f } }
}

Is this possible in C o开发者_高级运维r do I have to define the structures separately?


No, it doesn't work like that. You need explicit storage for each structure:

struct A { int n; void *config; };

struct AConfig { int a; char *b; };
struct BConfig { int a; float b; };

struct AConfig ac = { 1932, "hello" };
struct BConfig bc = { 14829, 33.4f };

const struct A table[] = {
    { 103, &ac },
    { 438, &bc }
};

Edit:

Another possibility is to utilize a union and C99 (-std=c99) named initializers:

enum config_type { CT_INT, CT_FLOAT, CT_STRING };

union config_value {
    int int_value;
    float float_value;
    const char* string_value;
};

struct config {
    enum config_type ctype;
    union config_value cvalue;
};

struct config sys_config[] = {
    { CT_INT, { .int_value = 12 }}, 
    { CT_FLOAT, { .float_value = 3.14f }}, 
    { CT_STRING, { .string_value = "humppa" }}};

void print_config( const struct config* cfg ) {
    switch ( cfg->ctype ) {
        case CT_INT: 
            printf( "%d\n", cfg->cvalue.int_value ); break;      
        case CT_FLOAT:
            printf( "%f\n", cfg->cvalue.float_value ); break;
        case CT_STRING:
            printf( "%s\n", cfg->cvalue.string_value ); break;
        default:
            printf( "unknown config type\n" );
    }       
}


You can use a union:

struct AConfig { int a; char *b; };
struct BConfig { int a; float b; };
struct A {
    int n;
    union {
        struct AConfig a;
        struct BConfig b;
    };
};

Note that a and b are in the exact same space in memory. So if you are going to use the A.a you should not use A.b and vice versa.

Since this is an anonymous union, you can reference both a and b as if they were direct fields of struct A:

struct A sa;
sa.n = 3;
sa.b.a = 4;
sa.b.b = 3.14;


It would work if BConfig had a float pointer to b.

By the way, maybe you need to refactor your code to fit to C syntax.

#include <stdio.h>
#include <stdlib.h>

typedef struct { int n; void *config; } Config;

typedef struct { int a; char *b; } AConfig;
typedef struct { int a; float *b; } BConfig;

int main(void) {
        AConfig A;
        BConfig B;
        A.a= 103;
        A.b= "hello";
        B.a= 438;
        B.b=(float *) malloc (sizeof(float));
        *(B.b)= 33.4f;
        const Config table[] = {
                { A.a, (void *) A.b },
                { B.a, (void *) B.b }
        };
        printf("Hi\n");
        return 0;
}


You may prefer a union. My union syntax is a little rusty, but something like this:

union config { char* c; float d; };
struct A {int n; int a; union config b;};

const struct A table[] = {
    {103, 1932, { .c = "hello" } },
    {14829, 438, { .d = 33.4f } }
};

You need C99 for the designated initalizer (the .c or .d in the table), and obviously some way to tell if you're accessing a char* or a float, but I assume you have that covered somewhere else.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号