[解決済み] コンパイラの奇妙な警告 C: 警告: 'struct' はパラメータリストの内部で宣言されています。
質問
C言語の癖を発見してしまい、とても困惑しています。C言語では、構造体が宣言される前に、その構造体へのポインタを使用することが可能です。これは非常に便利な機能で、構造体へのポインタを扱うときには宣言は関係ないため、理にかなっています。ただ、これが(意外にも)正しくないコーナーケースを1つ見つけたのですが、その理由をうまく説明できません。私には言語設計のミスのように見えます。
このコードを見てください。
#include <stdio.h>
#include <stdlib.h>
typedef void (*a)(struct lol* etc);
void a2(struct lol* etc) {
}
int main(void) {
return 0;
}
与える。
foo.c:6:26: warning: ‘struct lol’ declared inside parameter list [enabled by default]
foo.c:6:26: warning: its scope is only this definition or declaration, which is probably not what you want [enabled by default]
foo.c:8:16: warning: ‘struct lol’ declared inside parameter list [enabled by default]
この問題を取り除くには、単純に次のようにすればよい。
#include <stdio.h>
#include <stdlib.h>
struct lol* wut;
typedef void (*a)(struct lol* etc);
void a2(struct lol* etc) {
}
int main(void) {
return 0;
}
説明のつかない問題が、説明のつかない理由で解消された。なぜでしょうか?
この質問はC言語の動作(あるいはgccやclangのコンパイラの動作の可能性)についてのもので、私が貼り付けた特定の例ではないことに注意してください。
EDIT
なぜC言語が関数の引数リストで初めて構造体ポインタを使用する際に警告を発し、他のコンテキストでは許可するのか、その理由も説明しない限り、「宣言の順序は重要である」という回答は受け入れません。なぜそれが問題なのでしょうか?
解決方法は?
コンパイラが文句を言う理由を理解するには、C の "struct"s について 2 つのことを知る必要があります。
-
は、名前を付けるとすぐに(宣言されているがまだ定義されていない型として)作成されるため、最初に登場する
struct lol
は宣言を作成します。 - 通常の変数と同じように宣言のスコープに従います。
(
struct lol {
を宣言してから構造の定義を始めると、それは
struct lol;
または
struct lol *
または、"declare" のステップの後で停止するオープンブレースを持たない他の何か)。
宣言されているがまだ定義されていない構造体型は、C 言語で「不完全型」と呼ばれるものの一例です。 不完全型へのポインタは、そのポインタをたどろうとしない限り、使用することが許されています。
struct lol *global_p;
void f(void) {
use0(global_p); /* this is OK */
use1(*global_p); /* this is an error */
use2(global_p->field); /* and so is this */
}
つまり、ポインタに従うためには、型を完成させなければならないのです。
いずれにせよ、関数宣言に通常の
int
というパラメータがあります。
int imin2(int a, int b); /* returns a or b, whichever is smaller */
int isum2(int a, int b); /* returns a + b */
という変数があります。
a
と
b
は括弧の中で宣言されていますが、これらの宣言は邪魔にならないようにする必要があります。
次
関数宣言が再宣言されても文句を言われないようにするためです。
と同じことが起こります。
struct
というタグ名があります。
void gronk(struct sttag *p);
は
struct sttag
は構造体を宣言し、その宣言が流されるのは
a
と
b
. しかし、これは大きな問題を引き起こします。タグが消えてしまい、構造タイプに二度と名前を付けられなくなってしまうのです。 と書くと
struct sttag { int field1; char *field2; };
を定義するもので、新しい別の
struct sttag
, と同じように。
void somefunc(int x) { int y; ... }
int x, y;
は、新しい別の
x
と
y
とは異なり、ファイルレベルのスコープで
somefunc
.
幸いなことに、構造体を宣言(定義)すれば 前に 関数宣言を書くと、プロトタイプレベルの宣言はアウタースコープ宣言を "参照"します。
struct sttag;
void gronk(struct sttag *p);
これで、両方の
struct sttag
は "同じ" です。
struct sttag
を完成させると
struct sttag
のプロトタイプの中にあるものを完成させることになります。
gronk
もあります。
Re question edit: 確かに、struct, union, enumタグの動作を別の方法で定義して、プロトタイプからそのスコープにバブルアウトさせることは可能だったでしょう。 そうすれば、この問題は解決します。 しかし、そのようには定義されていません。 プロトタイプを発明したのはANSI C89委員会ですから(というか、当時のC++から盗んだのですが)、彼らのせいにしてください :-)
関連
-
[解決済み】C言語におけるファイルスコープでの可変長配列の変更
-
[解決済み】GCC Cコードで静的宣言が非静的宣言に続くことを解決するには?
-
[解決済み】エラー:イニシャライザー要素がロード時に計算可能でない
-
[解決済み】メモリー・クロバリング・エラー
-
[解決済み】警告:組み込み関数'printf'の非互換な暗黙の宣言(デフォルトで有効]
-
[解決済み】「複数の定義」「最初に定義されたのはここです」エラーについて
-
[解決済み】エラー:不明な型名'bool'
-
[解決済み】.axfファイルとは何ですか?
-
[解決済み】C言語でpow( )への未定義参照、math.hを含むにもかかわらず【重複】。
-
[解決済み】配列型char[]が代入できない [重複]。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】Cコンパイルエラーです。Idは1終了ステータスを返した
-
[解決済み】警告。この関数ではXが初期化されていない状態で使用される可能性があります。
-
[解決済み】Cygwin - Makefile-error: ターゲット `main.o' のレシピに失敗しました。
-
[解決済み] struct で "warning: useless storage class specifier in empty declaration" (警告: 空の宣言での無駄なストレージクラス指定子)
-
[解決済み] テスト
-
[解決済み] struct has no member named
-
[解決済み] [Solved] .Cファイルをコンパイルしています。アーキテクチャ x86_64 の未定義シンボル
-
[解決済み】0LLや0x0ULの意味は何ですか?
-
[解決済み】未定義参照 makefile が間違っているのかも?
-
[解決済み] テスト