为什么 for 语句中 init-statement 末尾的分号是强制性的?

Why is the semicolon at the end of the init-statement within the for statement mandatory?

这是 C++17 标准定义 for 语句的方式:

for ( init-statement conditionₒₚₜ ; expressionₒₚₜ  ) statement

我也看过 https://en.cppreference.com/w/cpp/language/for:

attr(optional) for ( init-statement condition(optional) ; iteration_expression(optional) ) statement

因此,我只能理解在使用for循环时init-statement不是可选的。换句话说,必须在 header 中初始化一些变量才能使用这种控制流机制。好吧,情况似乎并非如此,因为当我键入诸如

之类的代码时
for (; a != b; ++a)

假设我已经定义了这些变量,它运行得很好。我不仅没有在header中声明变量,还引用了之前在循环外定义的其他变量。如果我要提供一个 init-statement,它的 object 只能在 for 循环内使用,但似乎我可以使用在其他地方声明的变量就好了。

得出这个结论后,我认为我不需要第一部分:尝试删除分号以使其更具可读性(好吧,只是为了它)。它现在不会编译。编译器说它期望 ;,计算 a != b 就好像它不在 for 循环中一样:"C4552: '!=': 未使用表达式的结果" 最后得出结论:"C2143: syntax error: missing ';'在“)”之前.

您不需要 init-statement,但您确实需要分号。为什么我引用的这些资源最初没有明确说明这一点,还是以某种我视而不见的方式暗示了这一点?

分号是必需的,因为 init-statement 包括分号。

引自N3337 6.5迭代语句:

for (for-init-statement condition_{opt}; expression_{opt}) statement

for-init-statement:
    expression-statement
    simple-declaration

6.2表达式语句:

expression-statement:
    expression_{opt} ;

7 个声明:

simple-declaration:
    decl-specifier-seq_{opt} init-declaratior-list_{opt} ;
    attribute-specifier-seq decl-specifier-seq_{opt} init-declarator-list ;

如果您查找 init-statement 并跟踪 the possibilities,您会发现它们都需要一个尾随分号。

iteration-statement:
    for ( for-init-statement conditionₒₚₜ ; expressionₒₚₜ ) statement

for-init-statement:
    expression-statement
    simple-declaration

expression-statement:
    expressionₒₚₜ ;

simple-declaration:
    attribute-specifier-seqₒₚₜ decl-specifier-seqₒₚₜ init-declarator-listₒₚₜ ;

A for-init-statementexpression-statementsimple-declaration. expression-statement 有一个可选的表达式,但有一个强制分号。同样,简单声明的组件都是可选的,除了最后的分号。

Why didn't these resources I cited initially made this clear, or is it implied in some way I am blind to?

语言标准

您引用的第一个资源是 C++17 标准。语言标准的编写是精确和一致的。通常(如您的情况)细节被推迟到其他部分,因此无论使用频率如何,每个定义只出现一次。休闲编码员阅读的方便性不是优先考虑的问题。标准的第一句规定了文件的范围。

This document specifies requirements for implementations of the C++ programming language.

注意这些要求是针对谁的。它们用于 实现 ,更常见但不准确地称为“编译器”。该标准不是为那些编写 C++ 程序的人编写的;它是为那些编写 C++ 编译器(以及实现的其他部分)的人编写的。这就是为什么此资源不关心从程序员的角度阐明要点。

cppreference.com

编码人员通常需要进行大量解释才能从标准中提取他们需要的内容。这就是为什么有教语言的书籍和资源,例如您的第二个引文,cppreference.com。将标准的既定目的与 that of cppreference.com 进行对比:

Our goal is to provide programmers with a complete online reference for the C and C++ languages and standard libraries, i.e. a more convenient version of the C and C++ standards.

该网站的目标受众是程序员,而不是实施者。因此,标准的严苛精度已被更多的解释冲淡。它试图在严格的正确性和可读性之间取得平衡,对需要检查语言某些方面的细节的编码人员有一点同理心。

在这个特殊情况下,我认为他们做了合理的工作。我想你只是忽略了解释? 您复制了“正式语法”行。紧接着是“非正式语法”行,用 declaration-or-expression(optional) ; 替换了令人困惑的 init-statement ,清楚地表明分号是必需的,但分号之前不需要出现任何内容。 语法行之后是相关定义的列表。 init-statement 的定义表明它“可能是空语句 ;”。此外,定义以

结尾

Note that any init-statement must end with a semicolon ;, which is why it is often described informally as an expression or a declaration followed by a semicolon.

注意,定义直接在相关页面。这是网站在呈现方式上与标准不同的一种方式。由于网站不是最终权威,因此如果不一致则影响较小。这使它可以自由地重复自己,并冒定义不相同的风险。恰当的例子:init-statement 的定义在 if statement article 中重复(其中 init-statement 是可选的)。

也许重要的是阅读这些定义,而不是假设您已经知道它们的含义?