关于C#:为什么内部结构中不允许使用typedef?

Why is a typedef not allowed in the inner struct?

我有一个程序在现有的typedef结构中定义typedef结构,我想知道为什么会出现编译错误。

程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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;
}

编译时出现以下错误:

1
2
3
4
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’

但是,当我把程序改为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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;
 }

它编译成功。

为什么内部结构不允许typedef?


c不允许在结构成员声明中使用存储类说明符(typedef,也不允许使用staticextern。这在c99中6.7.2.1p1的结构和联合声明的语法中有规定。

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

您可以将6.7.2.1p1语法与声明的语法进行比较,其中声明符不是6.7p1中的函数参数或结构/联合成员,在这种情况下,允许使用存储类说明符。


struct定义中有typedef是相当奇怪的样式。

通常,在struct定义的{}之间出现的唯一事物是结构成员的声明。

正如Ouah所说,struct定义中的声明不能包括存储类说明符;存储类说明符是typedefexternstaticautoregister(c11加_Thread_local)。这种限制是有意义的,因为结构成员的存储完全由它所属的结构的存储决定。

typedef是一种特殊情况,它不指定存储类,但为了方便语法,它被视为存储类说明符。

您可以在一个结构定义中包含其他类型的声明;例如,正如您所看到的,您可以在另一个结构定义中嵌套一个结构声明。例如,这个程序是有效的(据我所知):

1
2
3
4
5
6
7
8
9
10
11
12
struct outer {
    struct inner {
        int x;
    };                        // line 4
    struct inner foo;
};

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

但是GCC警告嵌套声明:

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

(在我尝试之前,我会认为这是非法的。)

更新:gcc -pedantic-errors以致命错误拒绝了这一点,表明这是非法的。我会用标准来验证这是非法的。

我认为最好的做法是在结构中只包含成员声明。如果需要声明另一个类型,请在结构声明之外声明它。例如,我这样重写了问题中的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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;
}

(实际上,我会这样写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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;
}