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


125

コード:

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

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

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


8
C ++モード(可能性あり)でコンパイルするか、MSがまだ最後の千年紀に行き詰まっています。暗黙のは、int1999年にC標準から削除されました
イェンスGustedt

16
@JensGustedt MSVC ++はC89(およびC99のいくつかの機能)のみをサポートします。これはC ++コンパイラーに近いものです。
ntoskrnl 2014年

3
@Brandin:/ Wallオプションを使用すると、型指定子が欠落し、デフォルトのintがCでサポートされなくなったことを示す警告C4431が表示されます(Jensのコメントを参照)。明らかにこのコンパイラはサポートしているので、少し矛盾しています...
lee77

4
@JensGustedtその測定では、2012年にリリースされたGCC 4.7(およびそれ以降のバージョンも、おそらく手元にないのではないか)も「最後の千年紀に行き詰まっている」のです。フラグが指定されていない場合、通知なしでOPのコードをコンパイルします。

3
@delnan、私は少なくとも、OPが警告レベルをオンに切り替えていたと思いました。私は明らかに間違っていました。そしてある意味これは本当です、それらはまだデフォルトとしてC99(またはバリアント)を持っていないので、gccもまだそこに行き詰まっています。clangは、フラグがなくても構成について警告します。
イェンスガステッド2014年

回答:


240

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

このキーワードは、実際には基本型が存在しなかったCの先行Bからの残りである:すべてがあったint、へのポインタintのアレイ、int(*)宣言のいずれかであろう。autoまたはextrn[原文のまま]。C intはデフォルトの規則として「すべてが」を継承しているため、次のようにして整数を宣言できます。

auto a;
extern b;
static c;

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

unsigned d;  // actually unsigned int

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

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

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


7
いいえ、これは1999年以降、正当なCではありません。適切な最新のCコンパイラではこれを許可していません。
イェンスガステッド2014年

18
@JensGustedt VSは、最新のCコンパイラを提供するとは主張していません。すべての外観から、Cコンパイラの作業は何年も前に中止されました。それらは、人々がレガシーコードをコンパイルし続けることができるようにそれを供給するだけです。(もちろん、まともな最新のCコンパイラには、レガシーコードをサポートするオプションがあります。K&R Cのオプションも含まれます。)
James Kanze、2014年

23
@JensGustedt:よろしいですか?GCCとClangはどちらもC99モードでは警告を出しますが、以外ではエラーとは見なされません-Werror
Fred Foo 2014年

2
@larsman、はい、6.7.2ではその
Jens Gustedt

40
@JensGustedt-再いいえ、これは1999年以降、合法のCではありません。適切な最新のCコンパイラではこれを許可していません。最初のステートメントは正しいです。それは1999年以来違法です。私見、2番目のステートメントは正しくありません。まともなCコンパイラは、これを考慮に入れなければなりません。彼らがそれを許可しなかった場合に書き換える必要があるすべてのレガシーコードを見てください。私はこのコメントを拡張する答えを書きました。
David Hammen、2014年

35

これは「いいえ」に対する回答であり、拡張コメントでもあります。これは、1999年以来、正当なCではありません。適切な最新のCコンパイラではこれを許可していません。

はい、auto a=1;C1999(およびC2011)では違法です。これが違法になったからといって、最新の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モードで(もちろん診断付きで)コンパイルできる必要があります。


1
@larsmans-私はあなたがどこから来たのかを見ることができます。あなたは欲しい-ffs-please-stop-allowing-constructs-from-some-previous-millenniumコンパイラオプション、またはより簡潔に、-fstrict-complianceオプションを選択します。コンパイラでの不満:「-std = c11を使用したとき、古代のK&Rクルフトがコンパイルされるとは思っていませんでした。実際には、コンパイルしないようにしたかったのです!」
David Hammen、2014年

1
実際には、最悪の残骸をコンパイルするためにフラグをオンする必要があります。しかし、-std=c99より厳格になることは正しい方向への一歩となるでしょう:)
Fred Foo

1
使用する場合gcc -g -O3 -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror(SOの質問からのコードでも、私が日常的に使用するものです)、必要なものにかなり近づきます。GCCのデフォルトを少なくとも-std=c99、できれば-std=c11(または-std=gnu11;可能性が高い)にしたいのですが、それまでは、…これらのオプションを調整できます。-pedantic-Wshadow-Wold-style-declarationおよびいくつかの他に便利ですが、これはオプションの良い開始セットです。
ジョナサンレフラー、2014年

3
@DavidHammen:循環的複雑さ、プロジェクトマネージャー、会社のポリシーは、言語の要素ではありません。
ジェリーB

3
あなたはGCCに必要な動作を取得するためのフラグがある-pedantic-errors
τεκ

29

auto2011年以前の意味がCありC++ます。つまり、変数には自動有効期間、つまりスコープによって決定される有効期間があります。これはstatic、スコープに関係なく、変数が「永久に」存続する寿命などとは対照的です。autoはデフォルトの存続期間であり、明示的にスペルアウトされることはほとんどありません。このため、で意味を変更しても安全でしたC++

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

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

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


さて、実際にはCではauto a = 1が許可されており、自動ストレージ期間を持つint変数を意味します。
lee77

1
正しくは、「ストレージ期間」は、値のリスト「自動」、「静的」、「動的」、「スレッド」のいずれかを取ります。「寿命」は、オブジェクトの実際の寿命です。したがって、変数には「自動」の保存期間と「main関数のスコープの期間」という存続期間があります。
スティーブジェソップ2014年

@スティーブはい、私はそれを暗示することを意味していませんでした autostatic、2つの可能性しかあり。私は、C++(およびC)にかなり慣れていると思われる質問者をターゲットにした方法で私の回答を書こうとしていたので、詳細を少し手間取りました。多分それは悪い考えでした。彼らは遅かれ早かれカバーされる必要があります。
BoBTFish 2014年

1
@BoBTFish:ああ、私はそれについて文句を言っていませんでした。期間である「ライフタイム」と、より正確に「ストレージ期間カテゴリ」と呼ばれたかもしれない「ストレージ期間」の間のセマンティックの違いを拡張するつもりでした。
スティーブジェソップ2014年

この暗黙的なintものは1999
。– Jens Gustedt

8

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

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

int a=1;

これは現代のCでは非推奨(そしておそらく禁止されている)だと思います。しかし、一部の一般的なコンパイラはデフォルトでC90に設定されており(これは許可されていると思います)、不愉快なことに、具体的に要求した場合にのみ警告を有効にします。GCCでコンパイルし、C99を指定して-std=c99、またはで警告を有効にする-Wall-Wimplicit-int、警告を与えます:

warning: type defaults to int in declaration of a


5

Cではauto、同じことを意味しますregister、それは変数が自動記憶域期間を持つことを意味します:C ++ 11で行います。

そしてC99より前のCでは(そしてMicrosoftのコンパイラはC99もC11もサポートしていませんが、その一部をサポートしている可能性があります)、多くの場合、タイプを省略できます。 int

イニシャライザからの型は一切取りません。あなたはたまたま互換性のあるイニシャライザを選びました。


1
registerキーワードはC ++ 11で廃止されていませんか?
2014年

@sordidはい、そうです。C ++ 11に先立ち、autoregisterまったく同じ意味を持っていた(私が以前服用上の制約があったとコメントしregister-qualified変数のアドレスが、それはC ++のため間違っていました)。registerは非推奨ですが、今のところ古い意味を保持しています。

5
@JensGustedt:答えは彼らがそうであるとは言いません。これは、CではC ++ autoと同じ意味であると述べてregisterいます(どちらも自動ストレージ期間を意味し、他には何もありません)。
マイクシーモア2014年

3

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


3

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

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

auto
register
static
extern

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

{
        int Count;
        auto int Month;
}

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

intauto以下のコードのデフォルトタイプです:

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

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

/* Default-int */
main()
{
    reurn 0;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.