web-dev-qa-db-ja.com

宣言される前に構造体をtypedefする

私は初心者ではありません。次のイディオムに精通しています。

typedef struct Foo_ Foo;// I know typedef struct Foo Foo is fine, I'm just trying to make it clearer
struct Foo_
{
    int value;
    Foo *link;
};

名前(識別子)を宣言する前に使用することは許可されていないことを理解しているので、突然混乱しました。しかし、宣言ではtypedef struct Foo_ Foo、識別子Foo_はまだ存在しません!なぜコンパイラはこれが起こるのを許可するのですか?誰かがこれに光を当てて、この種の構文の正当性を私に説明してくれませんか?

ウィキペディアの引用:typedefの目的は、既存のタイプに代替名を割り当てることです。

---> 8 ---

たくさんの有益な情報をありがとうございました。

31
Need4Steed

これはまったく問題ありません。あなたのようなstructタグの最初の使用は、struct型の前方宣言です。

ただし、_Fooの使用法はnot準拠であることに注意してください。先頭にアンダースコアがあり、大文字が後に続く識別子は予約されています。そうしないでください。末尾の下線は問題ありません。

30
Jens Gustedt

これは6.7.2.3p8でカバーされています:

6.7.2.3タグ

セマンティクス
[...]

8- [構造体または共用体の定義]または[構造体として以外に、struct-or-union識別子の形式の型指定子が発生した場合-または-共用体宣言]であり、タグとしての識別子の他の宣言が表示されていない場合は、不完全な構造体または共用体型を宣言し、その型のタグとして識別子を宣言します。

型指定子struct Foo in typedef struct Foo Fooは定義に含まれていません(struct Foo {...};)または宣言(struct Foo;)したがって、6.7.2.3p8に該当します。

typedefについて特別なことは何もないことに注意してください。また、例えば書く

struct A { struct Foo *p; };

また、以前の定義または宣言を表示する必要はありません。

ただし、関数の宣言または定義では、次のようになります。

void foo(struct Foo *p);

if struct Fooが以前に宣言されていない場合、宣言のscopeは関数の宣言または定義になり、後続の宣言と型互換性はありません。 Fooの宣言または定義。

13
ecatmur
ISO c99 : 6.2.1 Scopes of identifiers

7

構造体、共用体、および列挙型のタグには、タグを宣言する型指定子にタグが出現した直後に始まるスコープがあります。

typedef struct _Foo Foo; // You can do this because it's just the typedef the new type

struct _Foo *myfoo ; // It's pointer to struct _Foo (an incomplete type)
                      //but make sure before using myfoo->value   
                    // struct definition should be available

struct _Foo MyFoo;  // It's  definition of MyFoo but don't forget 
                    // to give the definition of struct _Foo (gcc extension). 

struct _Foo;  // forward declaration

struct _Foo    // It's the definition
{
    int value;
    Foo *link;
};

単にfunctionsについては、関数の実際の定義の前にforward declarationまたはtypedefを実行するので、structでも実行できます。

void func(int );
typedef void (*func_t)(int);

void func(int x)
{
 //actual definition
}
4
Omkant

typedefは、型のエイリアスを作成するために使用されます。ただし、typedefを実行した場合、その型は必ずしも存在するとは限りません。

例えば、

あなたがするだけなら:

struct Foo;

プログラムのどこにもstruct Fooを定義しないと、コンパイルされます。コンパイラは、それがどこかで定義されていると想定して続行します。構造体を定義せずに使用した場合のみ、エラーが発生します。

typedefの場合も同様です。

3
P.P.

特定の状況では、宣言する前にstruct ...タイプを使用することが有効です。その時はいわゆる「不完全型」です。

たとえば、変数を「不完全な」構造体へのポインタとして宣言すること、および(ご覧のとおり)typedefを宣言することは有効です。

1
glglgl

これは、フォワード宣言と呼ばれます。前方宣言を使用すると、不完全な型が許可されているコンテキストでその名前を使用できます。

コンパイラはtypedefタグを「認識」し、typedefの後で、使用する前に宣言されているタイプがある限り、typeが見つかるまで保存します。

1
Mike