140

私は長い間、C ではすべての変数を関数の先頭で宣言する必要があると考えていました。C99 のルールは C++ と同じですが、C89/ANSI C の変数宣言の配置ルールは何ですか?

gcc -std=c89次のコードは、とを使用して正常にコンパイルされますgcc -ansi

#include <stdio.h>
int main() {
    int i;
    for (i = 0; i < 10; i++) {
        char c = (i % 95) + 32;
        printf("%i: %c\n", i, c);
        char *s;
        s = "some string";
        puts(s);
    }
    return 0;
}

C89/ANSI モードでの宣言csエラーの原因となるべきではありませんか?

4

8 に答える 8

165

sC89 または ANSI 標準の一部ではありませんが、GCC では を GNU 拡張として宣言できるため、正常にコンパイルされます。これらの基準に厳密に準拠したい場合は、-pedanticフラグを渡す必要があります。

cブロックの先頭での宣言は{ }、C89 標準の一部です。ブロックは関数である必要はありません。

于 2008-11-13T21:47:29.513 に答える
79

C89 では、すべての変数をスコープ ブロックの先頭で宣言する必要があります。

したがって、char c宣言は for ループ スコープ ブロックの先頭にあるため有効です。ただし、char *s宣言はエラーになるはずです。

于 2008-11-13T21:53:01.127 に答える
45

ブロックの先頭で変数宣言をグループ化することは、古い原始的な C コンパイラの制限によるものと思われます。最新の言語はすべて、ローカル変数の宣言を最新の時点、つまり最初に初期化される時点で行うことを推奨し、時には強制することさえあります。これにより、ランダムな値を誤って使用するリスクがなくなるためです。宣言と初期化を分離すると、可能な場合でも「const」(または「final」)を使用できなくなります。

残念ながら、C++ は、C との下位互換性のために古い最上位の宣言方法を受け入れ続けています (1 つの C 互換性が他の多くのものか​​ら引きずり出されています...)。しかし、C++ はそれから離れようとしています:

  • C++ 参照の設計では、このようなブロックのグループ化の最上位は許可されません。
  • C++ ローカルオブジェクトの宣言と初期化を分離すると、余分なコンストラクターのコストを無料で支払うことができます。引数のないコンストラクターが存在しない場合は、両方を分離することさえできません!

C99 は C を同じ方向に動かし始めます。

ローカル変数が宣言されている場所が見つからないことが心配な場合は、より大きな問題があることを意味します: 囲んでいるブロックが長すぎるため、分割する必要があります。

https://wiki.sei.cmu.edu/confluence/display/c/DCL19-C.+Minimize+the+scope+of+variables+and+functions

于 2010-11-05T11:11:33.847 に答える
22

構文上の観点ではなく保守性の観点から、少なくとも 3 つの考え方があります。

  1. 関数の先頭ですべての変数を宣言すると、それらが 1 か所にまとめられ、包括的なリストを一目で確認できるようになります。

  2. すべての変数は、最初に使用された場所のできるだけ近くで宣言してください。そうすれば、それぞれがなぜ必要なのかがわかります。

  3. 最も内側のスコープ ブロックの先頭ですべての変数を宣言すると、変数ができるだけ早くスコープ外になり、コンパイラがメモリを最適化し、意図しない場所で誤って変数を使用した場合に通知できるようになります。

私は通常、最初のオプションを好みます。他のオプションでは、宣言のためにコードを調べなければならないことがよくあるからです。すべての変数を前もって定義すると、デバッガーからの初期化と監視が容易になります。

より小さなスコープ ブロック内で変数を宣言することがありますが、それは正当な理由があるためであり、その数はほとんどありません。1 つの例としてfork()、子プロセスだけが必要とする変数を宣言するために、 の後があります。私にとって、この視覚的なインジケーターは、その目的を思い出させるのに役立ちます。

于 2008-11-13T22:05:49.820 に答える
8

他の人が指摘したように、「ペダンティック」チェックを使用しない限り、「C89」モードであっても、GCCはこの点で(および、呼び出される引数によっては他のコンパイラーも)寛容です。正直なところ、衒学的な知識を持たない正当な理由はあまりありません。高品質の最新のコードは、常に警告なしでコンパイルする必要があります (または、コンパイラにとって疑わしい特定のことを行っていることがわかっている場合は、エラーの可能性がほとんどありません)。

C89 では、各スコープ内の他のステートメントの前に変数を宣言する必要があります。後の標準では、宣言をより使いやすく (より直感的かつ効率的にすることができます)、特に「for」ループでのループ制御変数の宣言と初期化を同時に行うことができます。

于 2011-05-16T11:10:15.710 に答える
-1

明確な説明のために、gccバージョン4.7.0のマニュアルからいくつかのステートメントを引用します。

「コンパイラは、「c90」や「c ++ 98」などのいくつかの基本標準、および「gnu90」や「gnu ++ 98」などのそれらの標準のGNU方言を受け入れることができます。基本標準を指定することにより、コンパイラはその標準に準拠するすべてのプログラムと、それと矛盾しないGNU拡張機能を使用するプログラムを受け入れます。たとえば、「-std = c90」は、asmやtypeofキーワードなど、ISOC90と互換性のないGCCの特定の機能をオフにします。 ?:式の中間項を省略するなど、ISOC90では意味を持たない他のGNU拡張機能。」

あなたの質問の要点は、オプション「-std = c89」を使用しても、なぜgccがC89に準拠しないのかということだと思います。あなたのgccのバージョンはわかりませんが、大きな違いはないと思います。gccの開発者は、オプション「-std = c89」は、C89と矛盾する拡張機能がオフになっていることを意味していると言っています。したがって、C89で意味を持たない一部の拡張機能とは何の関係もありません。また、変数宣言の配置を制限しない拡張機能は、C89と矛盾しない拡張機能に属します。

正直なところ、オプション「-std = c89」を一目見ただけで、C89に完全に準拠する必要があると誰もが考えるでしょう。しかし、そうではありません。最初にすべての変数を宣言する問題は、良いか悪いかは習慣の問題です。

于 2012-08-12T06:51:23.383 に答える