Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C11 struct inheritance with anonymous struct

I saw this way to implement some kind of struct inheritance with anonymous struct in C11, and wanted to try it out. Here is what I have:

struct struct_a {
    int aa;
};

struct struct_b {
    struct struct_a;
    int bb;
};

int main(void)
{
    volatile struct struct_b my_b;
    my_b.aa = 5; /* not a member of my_b */
    my_b.bb = 6;

}

Result from gcc:

$ gcc -std=c11 struct_extend.c 
struct_extend.c:11:20: warning: declaration does not declare anything
     struct struct_a;
                    ^
struct_extend.c: In function ‘main’:
struct_extend.c:18:9: error: ‘volatile struct struct_b’ has no member named ‘aa’
     my_b.aa = 5; /* not a member of my_b */

Relevant:

$ gcc --version
gcc (Debian 6.3.0-18) 6.3.0 20170516

Is this not implemented in my compiler, or am I doing it wrong?

like image 834
Gauthier Avatar asked Oct 17 '17 07:10

Gauthier


3 Answers

According to GCC reference : use -fms-extensions flag, Which will enable the this feature.

  • Unless -fms-extensions is used, the unnamed field must be a structure or union definition without a tag (for example, ‘struct { int a; };’). If -fms-extensions is used, the field may also be a definition with a tag such as ‘struct foo { int a; };’, a reference to a previously defined structure or union such as ‘struct foo;’, or a reference to a typedef name for a previously defined structure or union type.

  • The option -fplan9-extensions enables -fms-extensions as well as two other extensions. First, a pointer to a structure is automatically converted to a pointer to an anonymous field for assignments and function calls.

I have used following command on GCC, it's working fine.

gcc -std=c11 -O2 -Wall -fms-extensions -pedantic -pthread ls.c
like image 173
msc Avatar answered Oct 24 '22 06:10

msc


The standard only allows structure and unions without a tag as unnamed members:

6.7.2.1 Structure and union specifiers - Paragraph 13

An unnamed member whose type specifier is a structure specifier with no tag is called an anonymous structure; an unnamed member whose type specifier is a union specifier with no tag is called an anonymous union. The members of an anonymous structure or union are considered to be members of the containing structure or union. This applies recursively if the containing structure or union is also anonymous.

Yours clearly has a tag, so it's not valid C. What the answer you linked to did is not any better either. The way to do it in a standard compliant way, is sadly quite verbose:

struct struct_b {
    union {
        struct struct_a _aa;
        struct { int aa; };
    };
    int bb;
};

Which really isn't anything to be impressed by. One can perhaps use a macro to avoid repeating the member declarations, but it's a code smell by now.

like image 4
StoryTeller - Unslander Monica Avatar answered Oct 24 '22 08:10

StoryTeller - Unslander Monica


It appears you are attempting to make an anonymous unnamed struct containing int aa in struct_b, similar to the following:

#include <stdio.h>

struct struct_b {
    struct {
        int aa;
    };
    int bb;
};

int main(void)
{
    volatile struct struct_b my_b;
    my_b.aa = 5; /* now a member of my_b */
    my_b.bb = 6;

    printf ("my_b.aa: %d\nmy_b.bb: %d\n", my_b.aa, my_b.bb);

    return 0;
}

Example Use/Output

$ ./bin/strc2
my_b.aa: 5
my_b.bb: 6

This follows directly from the standard section cited by StoryTeller.

like image 1
David C. Rankin Avatar answered Oct 24 '22 07:10

David C. Rankin