8

既存のtypedef構造体内にtypedef構造体を定義するプログラムがありますが、なぜコンパイルエラーが発生するのか疑問に思っています。

プログラムは次のとおりです。

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

コンパイル時に次のエラーが発生します::

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’  

しかし、私がプログラムを変更したとき

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が内部構造で許可されていないのはなぜですか?

4

2 に答える 2

14

Cは、構造体メンバーの宣言でストレージクラス指定子( typedef、だけでなく、staticまたは)を許可しません。externこれは、C99の6.7.2.1p1の構造体および共用体宣言の構文で指定されています。

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

6.7.2.1p1構文を、宣言子が6.7p1の関数パラメーターまたは構造体/共用体メンバーではない宣言の構文と比較して、この場合、ストレージクラス指定子が許可されていることを確認できます。

于 2012-06-11T17:27:55.297 に答える
5

struct定義内にtypedefを含めるのはかなり奇妙なスタイルです。

通常、{}の間に表示されるのstructは、構造体のメンバーの宣言だけです。

ouahが言うように、定義内の宣言にstructストレージクラス指定子を含めることはできません。ストレージクラスの指定子はtypedef、、、、、、およびです(C11はを追加しますextern)。構造体メンバーのストレージは、それがメンバーである構造体のストレージによって完全に決定されるため、この制限は理にかなっています。staticautoregister_Thread_local

そしてtypedef、これは特別な場合です。ストレージクラスは指定しませんが、構文上の便宜のためにストレージクラス指定子として扱われます。

構造体定義内に他の種類の宣言を含めることができます。たとえば、これまで見てきたように、構造体宣言を別の宣言の中にネストすることができます。たとえば、このプログラムは有効です(私が知る限り):

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

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

ただし、gccはネストされた宣言について警告します。

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

(そして、これを試す前は、違法だと思っていたでしょう。)

更新gcc -pedantic-errorsこれを致命的なエラーで拒否し、違法であることを示唆します。これが違法であることを標準で確認しようと思います。

ベストプラクティスは、構造体内にメンバー宣言のみを含めることだと思います。別の型を宣言する必要がある場合は、struct宣言の外で宣言してください。たとえば、次のような質問のコードを書き直します。

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

(実際、私はそれを次のように書きます:

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;
}
于 2012-06-11T20:36:11.483 に答える