タイトルが言うように、私はこのコードを持っています:
typedef struct Book{
int id;
char title[256];
char summary[2048];
int numberOfAuthors;
struct Author *authors;
};
typedef struct Author{
char firstName[56];
char lastName[56];
};
typedef struct Books{
struct Book *arr;
int numberOfBooks;
};
私はこれらのエラーをgccから受け取ります:
bookstore.c:8:2: error: unknown type name ‘Author’
bookstore.c:9:1: warning: useless storage class specifier in empty declaration [enabled by default]
bookstore.c:15:1: warning: useless storage class specifier in empty declaration [enabled by default]
bookstore.c:21:2: error: unknown type name ‘Book’
bookstore.c:23:1: warning: useless storage class specifier in empty declaration [enabled by default]
このようにtypedefを変更した場合:
typedef struct{
char firstName[56];
char lastName[56];
} Author;
その後、警告もエラーも発生しません。 http://www.Amazon.com/C-Programming-Language-2nd-Edition/dp/0131103628 を検索し、数時間グーグルで検索すると、最初の実装がなぜ失敗するのかわかりません」仕事。
ここでいくつかのことが行われています。最初に、他の人が言ったように、不明な型に関するコンパイラの不満は、型を使用する前に定義する必要があるためかもしれません。ただし、さらに重要なのは、(1)構造体定義、(2)構造体宣言、(3)typedefの3つのことの構文を理解することです。
構造体を定義するとき、構造体には名前を付けるか、名前を付けないことができます(名前が付けられていない場合は、すぐに使用する必要があります(これについては以下で説明します)。
struct Name {
...
};
これは、構造体変数を宣言するために使用できる「構造体名」と呼ばれる型を定義します。
struct Name myNameStruct;
これは、struct Name
型の構造体であるmyNameStruct
という変数を宣言します。
構造体を定義し、同時に構造体変数を宣言することもできます。
struct Name {
...
} myNameStruct;
前と同様に、これはstruct Name
型の構造体であるmyNameStruct
という変数を宣言します... ただし、型を定義すると同時にそれを行いますstruct Name
。
このタイプを再度使用して、別の変数を宣言できます。
struct Name myOtherNameStruct;
Typedefは、特定の名前を持つ型をエイリアスするための単なる方法です。
typedef OldTypeName NewTypeName;
上記のtypedefが与えられると、NewTypeName
を使用するときはいつでもOldTypeName
を使用するのと同じです。 Cプログラミング言語では、これは構造体で特に便利です。なぜなら、その型の変数を宣言するときにWordの「構造体」を省略できるためです構造体の名前を単に型として扱うためです独自の(C++で行うように)。次に、最初に構造体を定義し、次に構造体をtypedefする例を示します。
struct Name {
...
};
typedef struct Name Name_t;
上記のOldTypeNameはstruct Name
で、NewTypeNameはName_t
です。そのため、次のように記述する代わりに、struct Name型の変数を宣言します。
struct Name myNameStruct;
私は簡単に書くことができます:
Name_t myNameStruct;
また、typedefは構造体の定義と組み合わせることができます。これがコードで行っていることです:
typedef struct {
...
} Name_t;
これは、構造体に名前を付けるときにも実行できますが、これは不要です。
typedef struct Name {
...
} Name_t;
NOTE WELL:上記の構文では、 "typedef"で開始したため、ステートメント全体がtypedef
ステートメントになり、OldTypeNameがたまたま構造体定義になります。したがって、コンパイラーは、右中括弧}の後に来る名前afterをNewTypeNameとして解釈します...それは[〜 #〜] not [〜#〜]変数名(typedefなしの構文の場合と同様に、この場合、構造体を定義し、同時に構造体変数を宣言します)。
さらに、typedefを指定し、その後Name_tを終了すると、INCOMPLETE typedefステートメントが効果的に作成されます。コンパイラは「struct Name { ... }
」内のすべてをOldTypeNameと見なすため、 typedefにNewTypeNameを提供していません。これが、コンパイラがあなたが書いたコードに満足していない理由です(コンパイラのメッセージは、あなたが何を間違えたかよくわからないため、かなり謎めいていますが)。
さて、上で述べたように、定義時に構造体型に名前を付けない場合は、変数を宣言するためにすぐに使用する必要があります。
struct {
...
} myNameStruct; // declares myNameStruct as a variable with this struct
// definition, but the definition cannot be re-used.
または、typedefで名前のない構造体型を使用できます。
typedef struct {
...
} Name_t;
この最終構文は、あなたが書いたときに実際にしたことです:
typedef struct{
char firstName[56];
char lastName[56];
} Author;
そして、コンパイラは幸せでした。 HTH。
_tサフィックスに関するコメント/質問について:
_t接尾辞は、コードを読んでいる人に、_tの記号名が(変数名ではなく)型名であることを示すための規則です。コンパイラは_tを解析せず、認識しません。
C89、特にC99標準ライブラリは多くのタイプを定義し、それらのタイプの名前に_tを使用することを選択しました。たとえば、C89標準ではwchar_t、off_t、ptrdiff_tが定義されています。 C99標準では、uintptr_t、intmax_t、int8_t、uint_least16_t、uint_fast32_tなど、多くの追加の型が定義されています。ただし、_tは予約されておらず、コンパイラによって特別に解析も通知もされません。 Cで(typedefを介して)新しい型を定義する場合。C++では、多くの人が、Cの規則my_new_type_tとは対照的に、MyNewTypeなど、大文字で型名を開始する規則を使用します。 HTH
typedef
の構文は次のとおりです。
typedef old_type new_type
最初の試行では、struct Book
タイプおよびnotBook
。つまり、データ型はstruct Book
とBook
ではありません。
2番目の形式では、typedef
の正しい構文を使用したため、コンパイラはBook
という型を認識します。
私はあなたが理解するのに役立つと思う。 http://www.tutorialspoint.com/cprogramming/c_typedef.htm
bookstore.c:8:2: error: unknown type name ‘Author’
bookstore.c:21:2: error: unknown type name ‘Book’
これらは、使用する前に定義する必要があるため生成されます。構造体「Author」と「Books」を構造体「Book」の上に移動します。これで解決します。
また、問題が発生する理由を説明している警告は、構造体を適切にtypedefしていないためコンパイラが「typedef struct Author」を不要と識別し、コンパイラが「読み取る」ために有用なものがないことを示します。
あなたはすでに答えがこの形式であるべきであることを知っているので
typedef struct {
...
...
...
} struct-name;
それにこだわる。
Bookを定義する前にAuthorを定義する必要があります。
AuthorをBookで使用するため、事前に定義する必要があります。