web-dev-qa-db-ja.com

なぜauto a = 1; Cでコンパイルしますか?

コード:

int main(void)
{
    auto a=1;
    return 0;
}

ファイルの拡張子が.cの場合、MS Visual Studio 2012コンパイラによりエラーなしでコンパイルされます。 .c拡張子を使用する場合、コンパイルはC++ではなくC構文に従う必要があると常に考えていました。さらに、C++ 11以降のC++では、型のないautoが許可されている限りonly、つまり、初期化子。

それは私のコンパイラがCに固執していないことを意味しますか、それともC言語のコードは実際に正しいのですか?

124
lee77

autoは、「ローカルスコープ」を意味する古いCキーワードです。 auto aauto int aと同じであり、ローカルスコープは関数内で宣言された変数のデフォルトであるため、この例ではint aと同じです。

このキーワードは、実際にはCの先行Bからの残りであり、基本型はありませんでした。すべてがintintへのポインター、intの配列でした。(*)宣言はautoまたはextrn [sic]のいずれかですCはデフォルトのルールとして「すべてがint」であるため、次のように整数を宣言できます。

auto a;
extern b;
static c;

ISO Cはこれを取り除きましたが、多くのコンパイラは下位互換性のためにそれを受け入れています。馴染みがないように思える場合は、関連するルールが機能していることを理解する必要があります

unsigned d;  // actually unsigned int

これは現在のコードではまだ一般的です。

C++ 11はキーワードを再利用しましたが、C++プログラマーが元の意味で使用しているキーワードはほとんどありませんでしたが、型推論のために使用していました。 Cの「すべてはint」ルールがC++ 98ですでに削除されているため、これはほとんど安全です。壊れているのはauto T aだけで、これは誰も使用していません。 (彼の 言語の歴史に関する論文 のどこかで、Stroustrupはこれについてコメントしていますが、正確な参照は今のところ見つかりません。)

(*)Bでの文字列処理は興味深いものでした。intの配列を使用し、各メンバーに複数の文字をパックします。 Bは実際には BCPL であり、構文は異なります。

239
Fred Foo

これは、に対する答えと拡張コメントの両方です。いいえ、これは1999年以降の合法的なCではありません。まともな最新のCコンパイラはこれを許可していません。

はい、C1999(およびC2011)ではauto a=1;は違法です。これが現在違法であるからといって、最新のCコンパイラがそのような構造を含むコードを拒否する必要があるという意味ではありません。まともな現代のCコンパイラはこれをまだ許可しなければならない、というのはまったく逆だと主張します。

Clangとgccはどちらも、問題のサンプルコードを1999または2011バージョンの標準に対してコンパイルするときにそれを行います。両方のコンパイラーは診断を発行し、不快なステートメントがauto int a=1;であったかのように続行します。

私の意見では、これはまともなコンパイラーがすべきことです。診断を発行することにより、clangとgccは標準に完全に準拠します。規格は、コンパイラが違法なコードを拒否しなければならないとは言っていません。標準では、変換単位に構文規則または制約の違反が含まれる場合、適合実装は少なくとも1つの診断メッセージを生成する必要があるとのみ述べています(5.1.1.3)。

不正なコンストラクトを含むコードがある場合、適切なコンパイラーは不正なコードを理解しようとするため、コンパイラーはコード内の次のエラーを見つけることができます。最初のエラーで停止するコンパイラーは、あまり良いコンパイラーではありません。 auto a=1を理解する方法があります。これは、「暗黙のint」ルールを適用することです。このルールは、コンパイラがC90またはK&Rモードで使用されている場合、コンパイラがauto a=1であるかのようにauto int a=1を解釈することを強制します。

通常、ほとんどのコンパイラは、不正な構文を含むコードを拒否します(拒否:オブジェクトファイルまたは実行可能ファイルの生成を拒否します)。これは、コンパイラの作成者が、コンパイルに失敗することが最善の選択肢ではないと判断した場合です。最善の方法は、診断を発行し、コードを修正して続行することです。 register a=1;などのコンストラクトが点在するレガシーコードが多すぎます。コンパイラーは、そのコードをC99またはC11モードでコンパイルできるはずです(もちろん、診断を使用して)。

35
David Hammen

autoは、2011標準以前のCおよびC++で意味を持ちます。これは、変数に自動有効期間、つまり 有効期間はスコープによって決定される があることを意味します。これは、スコープに関係なく変数が「永久に」続くstaticライフタイムとは対照的です。 autoはデフォルトのライフタイムであり、明示的に記述されることはほとんどありません。これが、C++の意味を変更しても安全だった理由です。

99規格以前のCでは、変数のタイプを指定しない場合、デフォルトでintになります。

したがって、auto a = 1;を使用すると、int変数を宣言(および定義)し、有効期間はスコープによって決定されます。

(「ライフタイム」は「ストレージ期間」とより適切に呼ばれますが、おそらくそれほど明確ではないと思います)。

29
BoBTFish

CおよびC++の歴史的な方言では、autoaに自動ストレージがあることを意味するキーワードです。デフォルトでは自動であるローカル変数にのみ適用できるため、誰も使用しません。これが、C++がキーワードを再利用した理由です。

歴史的に、Cは型指定子のない変数宣言を許可していました。タイプのデフォルトはintです。したがって、この宣言は

int a=1;

これは、現代のCでは非推奨(およびおそらく禁止)であると思います。しかし、いくつかの一般的なコンパイラはデフォルトでC90(これは許可されていると思います)を使用し、面倒なことに、特に要求した場合にのみ警告を有効にします。 GCCでコンパイルし、-std=c99でC99を指定するか、-Wallまたは-Wimplicit-intで警告を有効にすると、警告が表示されます。

warning: type defaults to ‘int’ in declaration of ‘a’
8
Mike Seymour

Cでは、autoはC++ 11でregisterと同じことを意味します。つまり、変数に自動ストレージ期間があることを意味します。

Cの前のC(およびMicrosoftのコンパイラはC99とC11のいずれもサポートしていませんが、一部をサポートしている場合があります)では、多くの場合、タイプを省略できます。デフォルトはintです。

初期化子から型を取得しません。あなたはたまたま互換性のある初期化子を選んだのです。

5
user743382

ストレージクラスは、Cプログラム内の変数や関数のスコープ(可視性)と寿命を定義します。

Cプログラムで使用できる次のストレージクラスがあります。

auto
register
static
extern

autoは、すべてのローカル変数のデフォルトのストレージクラスです。

{
        int Count;
        auto int Month;
}

上記の例では、同じストレージクラスを持つ2つの変数を定義しています。 autoは、関数、つまりローカル変数内でのみ使用できます。

intは、以下のコードのautoのデフォルトタイプです。

auto Month;
/* Equals to */
int Month;

以下のコードも合法です:

/* Default-int */
main()
{
    reurn 0;
}
3
Amir Saniyan

Visual Studioのコンパイルタイプは、right click on file -> Properties -> C/C++ -> Advanced -> Compile Asで入手できます。 C force /TCオプションとしてコンパイルされていることを確認します。この場合、larsmansが言ったことです(古いC autoキーワード)。知らないうちにC++としてコンパイルされる場合があります。

3
UmNyobe