これがCでコンパイルされないとき、私は混乱していました:
int main()
{
for (int i = 0; i < 4; ++i)
int a = 5; // A dependent statement may not be declaration
return 0;
}
私はこれがコンパイルされるC++に慣れています。私はここでSOでCとC++の異なるものがどのように「ステートメント」と見なされるかについての答えを思い出すまで、しばらくumb然として見つめていました。これはswitchステートメントに関してでした。 "forループブラケットはCとC++の両方に存在する必要があります。これは、セミコロンを追加するか{}波線ブラケットブロックを作成することの両方で実行できます。
C++では、「int a = 7;」宣言、定義、および初期化と見なされます。 Cでは、これらのすべてと見なされますが、Cでは「ステートメント」とは見なされません。
誰かがCでなぜこれがステートメントではないのかを正確に明確にすることができますが、C++ではそうですか?ある言語がそうであると言い、別の言語がそうでないと言うので、これはステートメントが何であるかという私の概念を混乱させているので、私はちょっと混乱しています。
C++では、ステートメントは(C++ 17標準ドラフト)
excerpt from [gram.stmt]
statement:
labeled-statement
attribute-specifier-seqopt expression-statement
attribute-specifier-seqopt compound-statement
attribute-specifier-seqopt selection-statement
attribute-specifier-seqopt iteration-statement
attribute-specifier-seqopt jump-statement
declaration-statement
attribute-specifier-seqopt try-block
init-statement:
expression-statement
simple-declaration
declaration-statement:
block-declaration
...
C++には、宣言であり、ステートメントである宣言ステートメントがあることに注意してください。同様に、単純な宣言はinitステートメントです。ただし、すべての宣言がステートメントではありません。宣言の文法には、ステートメントのリストにないものが含まれています。
excerpt from [gram.dcl]
declaration:
block-declaration
nodeclspec-function-declaration
function-definition
template-declaration
deduction-guide
explicit-instantiation
explicit-specialization
linkage-specification
namespace-definition
empty-declaration
attribute-declaration
block-declaration:
simple-declaration
asm-definition
namespace-alias-definition
using-declaration
using-directive
static_assert-declaration
alias-declaration
opaque-enum-declaration
simple-declaration:
decl-specifier-seq init-declarator-listopt ;
attribute-specifier-seq decl-specifier-seq init-declarator-list ;
attribute-specifier-seqopt decl-specifier-seq ref-qualifieropt [ identifier-list ] initializer ;
...
宣言文法のリストは、数ページ続きます。
Cでは、ステートメントは(C11標準ドラフト)
excerpt from Statements and blocks
statement:
labeled-statement
compound-statement
expression-statement
selection-statement
iteration-statement
jump-statement
Cのステートメントである宣言はないことに注意してください。
したがって、statementの意味は言語によって明らかに異なります。 C++のステートメントは、Cのステートメントよりも広い意味を持つようです。
C++では、反復ステートメントの「サブステートメント」が暗黙的に複合ステートメント([stmt.iter])であることが許可されました
反復ステートメントのサブステートメントが複合ステートメントではなく単一ステートメントである場合、元のステートメントを含む複合ステートメントに書き換えられたかのようになります。例:
while (--x >= 0)
int i;
同等に書き換えることができます
while (--x >= 0) {
int i;
}
c標準にはこの言語はありません。
さらに、C++ではstatementの定義が変更され、declaration statementが含まれるようになりました。したがって、上記の変更が行われなかったとしても、それは依然として有効です。
中括弧を追加すると機能する理由は、宣言がcompound-statementになり、宣言を含めることができるようになったためです。
中括弧なしのループ本体にidentifierを含めることが許可されているため、代わりにこれを行うことができます。
int a = 5;
for (int i = 0; i < 4; ++i)
a;
Cppreferenceによると、 C++ には次のタイプのstatements
が含まれます。
[〜#〜] c [〜#〜] は、次のタイプのstatements
を考慮します。
お気づきのように、Cの宣言はstatements
とは見なされませんが、C++の場合はそうではありません。
C++の場合:
int main()
{ // start of a compound statement
int n = 1; // declaration statement
n = n + 1; // expression statement
std::cout << "n = " << n << '\n'; // expression statement
return 0; // return statement
} // end of compound statement
Cの場合:
int main(void)
{ // start of a compound statement
int n = 1; // declaration (not a statement)
n = n+1; // expression statement
printf("n = %d\n", n); // expression statement
return 0; // return statement
} // end of compound statement, end of function body
C++では宣言はステートメントですが、Cでは宣言はステートメントではありません。このforループのC文法に従って
for (int i = 0; i < 4; ++i)
int a = 5;
int a = 5;ループのサブステートメントである必要があります。ただし、これは宣言です。
たとえば、複合ステートメントを使用して、Cでコンパイルするコードを作成できます。
for (int i = 0; i < 4; ++i)
{
int a = 5;
}
ただし、コンパイラは変数a
が使用されていないことを示す診断メッセージを発行できます。
C宣言ではステートメントではないというもう1つの結果。 Cの宣言の前にラベルを配置することはできません。たとえば、このプログラム
#include <stdio.h>
int main(void)
{
int n = 2;
L1:
int x = n;
printf( "x == %d\n", x );
if ( --n ) goto L1;
return 0;
}
c ++プログラムとしてコンパイルされますが、Cではコンパイルされません。ただし、ラベルの後にヌルステートメントを配置すると、プログラムはコンパイルされます。
#include <stdio.h>
int main(void)
{
int n = 2;
L1:;
int x = n;
printf( "x == %d\n", x );
if ( --n ) goto L1;
return 0;
}