Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is a typedef not allowed in the inner struct?

I have a program that defines a typedef struct within an existing typedef struct, and I am wondering why I am getting a compilation error.

Here is the program:

typedef struct Outer
{
    typedef struct Inner
    {
        int b;
    }INNER;


    INNER inner;
    int a; 

}OUTER;

int main()
{ 
    OUTER obj;
    obj.a = 10;
    obj.inner.b=8;
    return 0;
}   

on compilation gives following error ::

test.c:3:5: error:expected specifier-qualifier-list before ‘typedef’
test.c: In function ‘main’:
test.c:17:5: error: ‘OUTER’ has no member named ‘a’
test.c:18:5: error: ‘OUTER’ has no member named ‘inner’  

but, when I changed the program to

typedef struct Outer
{
    struct Inner
    {
        int b;
    };

    struct Inner inner;
    int a; 

 }OUTER;

 int main()
 {
    OUTER obj;
    obj.a = 10;
    obj.inner.b=8;
    return 0;
 }   

it compiles successfully.

Why is typedef not allowed with inner structures?

like image 793
Eight Avatar asked Jun 11 '12 16:06

Eight


2 Answers

C does not allow a storage-class specifier (typedef, but also static or extern) in the declaration of a structure member. This is specified in the syntax of structures and unions declaration in 6.7.2.1p1 in C99.

/* The compiler will issue a diagnostic for this declaration */ 
struct s {    
    static int a;
};

You can compare 6.7.2.1p1 syntax with the syntax of a declaration where the declarator is not a function parameter or a structure / union member in 6.7p1 and see that in this case the storage-class specifiers are allowed.

like image 146
ouah Avatar answered Oct 18 '22 17:10

ouah


It's rather odd style to have a typedef inside a struct definition.

Normally the only things that should appear between the { and } of a struct definition are declarations of members of the structure.

As ouah says, a declaration within a struct definition cannot include a storage class specifier; the storage class specifiers are typedef, extern, static, auto, and register (and C11 adds _Thread_local). This restriction makes sense because the storage for a struct member is determined entirely by the storage of the structure of which it's a member.

And typedef is a special case; it doesn't specify a storage class, but it's treated as a storage class specifier for syntactic convenience.

You can have other kinds of declarations inside a struct definition; for example, as you've seen, you can nest a struct declaration inside another. For example, this program is valid (as far as I can tell):

struct outer {
    struct inner {
        int x;
    };                        // line 4
    struct inner foo;
};

int main(void) {
    struct outer obj;
    obj.foo.x = 42;
    return 0;
}

But gcc warns about the nested declaration:

c.c:4:6: warning: declaration does not declare anything [enabled by default]

(And before I tried this, I would have assumed it was illegal.)

UPDATE : gcc -pedantic-errors rejects this with a fatal error, suggesting it's illegal. I'll try to verify with the standard that this is illegal.

I think the best practice is to have only member declarations inside a struct. If you need to declare another type, declare it outside the struct declaration. For example, I'd rewrite the code in the question like this:

typedef struct Inner
{
    int b;
} INNER;

typedef struct Outer
{
    INNER inner;
    int a;

} OUTER;

int main(void)
{
    OUTER obj;
    obj.a = 10;
    obj.inner.b=8;
    return 0;
}

(Actually, I'd write it like this:

struct inner {
    int b;
};

struct outer {
    struct inner inner;
    int a;
};

int main(void) {
    struct outer obj;
    obj.a = 10;
    obj.inner.b = 8;
    return 0;
}
like image 27
Keith Thompson Avatar answered Oct 18 '22 18:10

Keith Thompson