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.
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.
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;
Selon cppreference, C++ inclut les types suivants de statements
:
Alors que C considère les types suivants de statements
:
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
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;
}