0

私はこの問題で輪になって走っています。extern.hで宣言された構造体があります:

typedef struct {
    char data[Q_SIZE];
    int head;
    int tail;
    int size;
}queue;

main.cで、この構造体の2つのインスタンスを宣言します。

queue rxq, txq;

他の.cファイルでは、これらの構造体が使用されている場合、それらはグローバルexternとして宣言されます。

extern queue rxq, txq;

queue.cには、これらの構造体の1つへのポインターをパラメーターとして受け入れるいくつかの関数があります。

int QGetSize(queue * q)
{
    return q->size;
}

私のコンパイラでは、これらの関数のプロトタイプを作成する必要がありますが、プロトタイプを作成する方法が好きではありません。

int QGetSize(queue *);
ERROR: parse error at near '*'

int QGetSize(queue);
ERROR: invalid functions argument declaration

int QGetSize(struct *);  // this is the one that to me, should work. the other errors make sense.
ERROR: parse error at near '*'

int QGetSize(struct);
ERROR: parse error at near ')'

int QGetSize(struct queue *);
WARNING: struct declared inside parameter list

おそらく、prototype.hファイル内では、この構造体のようにキューのtypedefではないことに注意することが重要です。typedefを実行したり、再定義したり、最初に宣言された場所に.hファイルを含めたりすると、さらにエラーが発生します。

4

3 に答える 3

3

インクルード ガードを使用して、同じファイルが繰り返しインクルードされるのを防ぐことができます。

#ifndef FILE_H
#define FILE_H

/* Declarations etc. here. */

#endif

そうすれば、typedef で観察したような再定義から自動的に保護されます。アンダースコアで始まるマクロがインクルード ガードとして使用されることがよくありますが、これらの名前は実装の名前空間にあり、予約されているため、これは悪い習慣です。

于 2012-11-07T22:24:39.170 に答える
1

コンパイラエラーに関して:

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

これが必要になることはめったにありませんが、非常にねじれた循環依存関係が発生することがあります。そんな時、これで窮地を脱することができます。(これが、上記の最後のコンパイラ警告がエラーではなく警告である理由でもあります。コンパイラは、未知の構造体引数を前方宣言として解釈しました。これは正当ですが、悪い考えです。)

とにかく、これがお役に立てば幸いです。

于 2012-11-07T23:02:40.543 に答える
0

C には、型の 2 つの異なる名前空間があります。struct/union/enum タグ名の名前空間と typedef 名の名前空間です。

typedef struct {
    ...
}queue;

上記の宣言は、無名構造を宣言し、その typedef を作成します。typedef 名前空間には名前しかありませんが、タグ名前空間には名前がありません。これは、前方宣言できないことを意味します。前方宣言を行う場合は、タグの名前空間で名前を付ける必要があります。

このhttps://stackoverflow.com/a/612350/1450257をさらに参照してください

于 2012-11-07T22:50:30.130 に答える