私は初心者ではありません。次のイディオムに精通しています。
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 ---
たくさんの有益な情報をありがとうございました。
これはまったく問題ありません。あなたのようなstruct
タグの最初の使用は、struct
型の前方宣言です。
ただし、_Foo
の使用法はnot準拠であることに注意してください。先頭にアンダースコアがあり、大文字が後に続く識別子は予約されています。そうしないでください。末尾の下線は問題ありません。
これは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
の宣言または定義。
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
}
typedef
は、型のエイリアスを作成するために使用されます。ただし、typedefを実行した場合、その型は必ずしも存在するとは限りません。
例えば、
あなたがするだけなら:
struct Foo;
プログラムのどこにもstruct Foo
を定義しないと、コンパイルされます。コンパイラは、それがどこかで定義されていると想定して続行します。構造体を定義せずに使用した場合のみ、エラーが発生します。
typedef
の場合も同様です。
特定の状況では、宣言する前にstruct ...
タイプを使用することが有効です。その時はいわゆる「不完全型」です。
たとえば、変数を「不完全な」構造体へのポインタとして宣言すること、および(ご覧のとおり)typedef
を宣言することは有効です。
これは、フォワード宣言と呼ばれます。前方宣言を使用すると、不完全な型が許可されているコンテキストでその名前を使用できます。
コンパイラはtypedefタグを「認識」し、typedefの後で、使用する前に宣言されているタイプがある限り、typeが見つかるまで保存します。