web-dev-qa-db-ja.com

CおよびC ++のステートメントとしての宣言/定義

これが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++ではそうですか?ある言語がそうであると言い、別の言語がそうでないと言うので、これはステートメントが何であるかという私の概念を混乱させているので、私はちょっと混乱しています。

38
Zebrafish

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のステートメントよりも広い意味を持つようです。

11
eerorika

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;
16
AndyG

Cppreferenceによると、 C++ には次のタイプのstatementsが含まれます。

  1. 式ステートメント。
  2. 複合ステートメント。
  3. 選択ステートメント。
  4. 反復ステートメント。
  5. ジャンプ文。
  6. 宣言文;
  7. ブロックを試してください。
  8. アトミックブロックと同期ブロック

[〜#〜] c [〜#〜] は、次のタイプのstatementsを考慮します。

  1. 複合文
  2. 式ステートメント
  3. 選択ステートメント
  4. 反復ステートメント
  5. ジャンプ文

お気づきのように、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
7
Abhishek Keshri

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;
}
2