提问人:Zebrafish 提问时间:4/17/2018 最后编辑:Matteo ItaliaZebrafish 更新时间:9/12/2019 访问量:7470
在 C 和 C++ 中作为语句的声明/定义
Declarations/definitions as statements in C and 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++ 中不同的东西如何被视为“语句”。这是关于switch语句的。for 循环括号后面的“语句”必须同时存在于 C 和 C++ 中。这可以通过添加分号或创建 { } 波浪形括号块来完成。
在 C++ 中,“int a = 7;”被视为声明、定义和初始化。在 C 中,我相信它也被认为是所有这些,但在 C 中,它不被视为“语句”。
有人可以确切地澄清为什么在 C 中这不是一个语句,而在 C++ 中它是?这混淆了我对语句的概念,因为一种语言说它是,另一种说它不是,所以我有点困惑。
答:
C++ 允许迭代语句的“子语句”隐式是复合语句 ([stmt.iter])
如果迭代语句中的子语句是单个语句而不是复合语句,则就好像 它被重写为包含原始语句的复合语句。例:
while (--x >= 0)
int i;
可以等效地改写为
while (--x >= 0) {
int i;
}
C 标准没有这种语言。
此外,语句的定义在 C++ 中更改为包含声明语句,因此即使没有进行上述更改,它仍然是合法的。
添加大括号使其起作用的原因是,您的声明现在变成了一个可以包含声明的复合语句。
您可以在不带大括号的循环体中具有标识符,因此您可以改为执行此操作:
int a = 5;
for (int i = 0; i < 4; ++i)
a;
评论
在 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 中没有声明是语句。
因此,语句的含义在语言中明显不同。 C++ 语句似乎比 C 语句具有更广泛的含义。
根据 cppreference,C++ 包括以下类型:statements
- 表达式语句;
- 复合语句;
- 遴选声明;
- 迭代语句;
- 跳转语句;
- 声明声明;
- 尝试块;
- 原子块和同步块
而 C 考虑以下类型:statements
- 复合语句
- 表达式语句
- 选择语句
- 迭代语句
- 跳转语句
正如你所注意到的,在C语言中不考虑声明,而在C++中则不是这种情况。statements
对于 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
评论
在 C++ 中,声明是语句,而在 C 中,声明不是语句。所以根据这个for循环中的C语法
for (int i = 0; i < 4; ++i)
int a = 5;
整数 a = 5;必须是循环的子语句。然而,这是一个声明。
例如,您可以使用复合语句使代码在 C 中编译
for (int i = 0; i < 4; ++i)
{
int a = 5;
}
尽管编译器可以发出一条诊断消息,指出未使用该变量。a
另一个后果是,在 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;
}
不用 C 编译,尽管它编译为 C++ 程序。但是,如果在标签后放置一个 null 语句,则程序会编译。
#include <stdio.h>
int main(void)
{
int n = 2;
L1:;
int x = n;
printf( "x == %d\n", x );
if ( --n ) goto L1;
return 0;
}
下一个:我可以一次检查一小群布尔值吗?
评论