web-dev-qa-db-fra.com

Déclarations / définitions sous forme d'instructions en C et C ++

J'étais confus quand cela ne compilait pas en C:

int main()
{
    for (int i = 0; i < 4; ++i)
        int a = 5; // A dependent statement may not be declaration

    return 0;
}

Je suis habitué au C++ où cela se compilera. J'ai juste regardé abasourdi pendant un certain temps jusqu'à ce que je me souvienne d'une réponse ici sur SO sur la façon dont en C et C++ différentes choses sont considérées comme des "instructions". C'était à propos d'une instruction switch. Une "instruction" "après que les crochets de boucle for doivent être présents à la fois en C et C++. Cela peut être fait à la fois en ajoutant un point-virgule ou en créant un bloc de crochets {}.

En C++ "int a = 7;" est considéré comme une déclaration, une définition et une initialisation. En C, je pense qu'il est également considéré comme tout cela, mais en C, il n'est pas considéré comme une "déclaration".

Quelqu'un pourrait-il expliquer exactement pourquoi en C ce n'est pas une déclaration alors qu'en C++ c'est le cas? Cela brouille mon concept de ce qu'est une déclaration, car une langue le dit et une autre dit que ce n'est pas le cas, donc je suis un peu confus.

38
Zebrafish

En C++, une déclaration est (brouillon standard 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

...

Notez qu'il existe des instructions de déclaration en C++, qui sont des déclarations et sont des instructions. De même, les déclarations simples sont des instructions init. Cependant, toutes les déclarations ne sont pas des déclarations. La grammaire des déclarations contient des choses qui ne figurent pas dans la liste des déclarations:

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 ;

...

La liste des grammaires de déclaration continue sur quelques pages.


En C, une déclaration est (projet standard C11)

excerpt from Statements and blocks

statement:
    labeled-statement
    compound-statement
    expression-statement
    selection-statement
    iteration-statement
    jump-statement

Notez qu'aucune déclaration n'est une déclaration en C.


Ainsi, la signification de instruction est clairement différente dans les langues. L'instruction en C++ semble avoir un sens plus large que l'instruction en C.

11
eerorika

C++ a permis que la "sous-déclaration" d'une instruction d'itération soit implicitement une instruction composée ([stmt.iter])

Si la sous-instruction d'une instruction d'itération est une instruction unique et non une instruction composée, c'est comme si elle avait été réécrite pour être une instruction composée contenant l'instruction d'origine. Exemple:

while (--x >= 0)
   int i;

peut être réécrit de manière équivalente

while (--x >= 0) {
   int i;
}

la norme C n'a pas ce langage.

De plus, la définition d'un déclaration a été modifiée en C++ pour inclure un déclaration déclaration, donc même si la modification ci-dessus n'était pas effectuée, elle serait toujours légale.


La raison pour laquelle l'ajout d'accolades le fait fonctionner est que votre déclaration devient maintenant un compound-statement qui peut inclure des déclarations.

Vous êtes autorisé à avoir un identifiant dans un corps de boucle sans accolades, vous pouvez donc le faire à la place:

int a = 5;
for (int i = 0; i < 4; ++i)
    a;
16
AndyG

Selon cppreference, C++ inclut les types suivants de statements:

  1. déclarations d'expression;
  2. déclarations composées;
  3. déclarations de sélection;
  4. déclarations d'itération;
  5. instructions de saut;
  6. déclarations de déclaration;
  7. essayez les blocs;
  8. blocs atomiques et synchronisés

Alors que C considère les types suivants de statements:

  1. déclarations composées
  2. déclarations d'expression
  3. déclarations de sélection
  4. instructions d'itération
  5. instructions de saut

Comme vous pouvez le constater, les déclarations ne sont pas considérées comme statements en C, alors que ce n'est pas le cas en C++.

Pour 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

Pour 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

En C++, les déclarations sont des instructions tandis qu'en C, les déclarations ne sont pas des instructions. Donc, selon la grammaire C dans cette boucle

for (int i = 0; i < 4; ++i)
    int a = 5;

int a = 5; doit être une sous-déclaration de la boucle. Mais c'est une déclaration.

Vous pouvez créer le code à compiler en C en utilisant l'instruction composée comme par exemple

for (int i = 0; i < 4; ++i)
{
    int a = 5;
}

bien que le compilateur puisse émettre un message de diagnostic indiquant que la variable a n'est pas utilisée.

Encore une conséquence qu'en C, les déclarations ne sont pas des déclarations. Vous ne pouvez pas placer d'étiquette avant une déclaration en C. Par exemple, ce programme

#include <stdio.h>

int main(void) 
{
    int n = 2;

    L1:
    int x = n;

    printf( "x == %d\n", x );

    if ( --n ) goto L1; 

    return 0;
}

ne compile pas en C bien qu'il compile en tant que programme C++. Cependant, si pour placer une instruction null après l'étiquette, le programme compile.

#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
Vlad from Moscow