コンパイラエラーに関して:
int QGetSize(queue *);
ERROR: parse error at near '*'
これはおそらく、extern.h をインクルードしていないか、インクルードしている場合は「queue」の typedef が定義されていないためです。型であるはずなのに (まだ) 型として定義されていない単語を見つけると、C は非常に混乱します。
int QGetSize(queue);
ERROR: invalid functions argument declaration
同上。定義は、使用前に表示する必要があります。
int QGetSize(struct *);
ERROR: parse error at near '*'
これは無効です。「構造体」は型ではありません。「構造体キュー」はタイプです。つまり、意味を持たせるには、'struct' の後に type タグを指定する必要があります。
int QGetSize(struct);
ERROR: parse error at near ')'
同上。また、コンパイラは「構造体」の後に別の単語を期待しており、単語がない場合は非常に混乱します。
int QGetSize(struct queue *);
WARNING: struct declared inside parameter list
これは、タイプ「struct queue」が定義されていないことを意味します。そうではありません。「typedef struct { ... } queue」は「struct queue { ... }」とは異なります。
だからここにいくつかのアドバイスがあります:
まず、標準的な方法は、ヘッダー ファイルの本文を「#ifndef」でラップして、1 回だけインクルードされるようにすることです。
#ifndef __HDR_H
#define __HDR_H
... code goes here ...
#endif
(__HDR_H は一意である必要があり、通常はファイル名のバリエーションです。)
次に、型を定義するヘッダーを、それらを使用する任意のファイルにいつでも #include できます。#ifndef (通常) を使用すると、問題なくインクルードできます。
次に、構造体タグと typedef の違いを理解する必要があります。
構造体タグは、特定の構造体定義の名前です。
struct queue { ... }; // Defines struct queue
struct queue foo; // foo is a queue structure.
typedef は、既存の型のエイリアスです。
typedef int HANDLE; // HANDLE is just another way of saying 'int'
typedef struct queue QUEUE; // QUEUE is shorthand for 'struct queue'
2つは非常に異なるものです。1 つ目は特定のタイプの構造を定義し、2 つ目は既存のタイプの新しい名前を作成します。実際、それらを組み合わせることができます。
typedef struct queue { ... } QUEUE;
特に「構造体キュー」に別の「構造体キュー」へのポインターが含まれている場合は、しばしばそうします。
だからこれで:
QUEUE foo;
struct queue bar;
'foo' と 'bar' はまったく同じ型です。
(また、これに少し関連しています。C では、typedef 名をすべて大文字にするのが一般的です。)
第三に、typedef は控えめに使用する必要があります。あなたの場合、それを完全に取り除き、常に「struct」キーワードを使用することをお勧めします。これにより、ローカル構造体変数の宣言に「struct」が含まれているため、何が起こっているのかを簡単に知ることができます。そのため、カジュアルな読者は、名前が変更された int ではなく構造体であることがわかります。
さらに重要なことは、コンパイラがより意味のあるエラー メッセージを表示できるようにすることです。構造体が未定義で、コンパイラが次のように表示する場合:
int foo(struct bar x);
bar が構造体であることを認識しているため、全体がパラメーター宣言であり、「struct bar」が未定義であることがわかります。ただし、これが表示された場合:
int foo(BAR x);
BAR がどうあるべきかわからないので、エラー メッセージは大きな WTF になる傾向があります?!?!?!?!? 代わりは。
最後に、'struct' 形式を使用すると、構造体を事前に宣言できます。
struct bar;
int foo (struct bar x);
struct bar { ... };
これが必要になることはめったにありませんが、非常にねじれた循環依存関係が発生することがあります。そんな時、これで窮地を脱することができます。(これが、上記の最後のコンパイラ警告がエラーではなく警告である理由でもあります。コンパイラは、未知の構造体引数を前方宣言として解釈しました。これは正当ですが、悪い考えです。)
とにかく、これがお役に立てば幸いです。