C++中“for”循环的范围规则与C中不同? [复制]

Posted

技术标签:

【中文标题】C++中“for”循环的范围规则与C中不同? [复制]【英文标题】:Scope rules of `for` loop different in C++ than in C? [duplicate] 【发布时间】:2021-11-10 10:47:42 【问题描述】:

我注意到for 循环的范围规则对于 C 和 C++ 是不同的。 例如,下面的代码在 C 编译器中是合法的,但在 C++ 编译器中是不合法的。

for (int i = 0; i < 10; ++i) 
    int i = 5;

以上代码在 C 中有效,但在 C++ 中出现重新定义错误。 我的猜测是 C 编译器将循环视为循环内有另一个作用域,如下所示。

for (int i = 0; i < 10; ++i) 
    
        int i = 5;
    

为什么 C 编译器允许在循环范围内定义第二个同名变量?这样做有什么特别的理由或优势吗?

【问题讨论】:

你有用例吗?能够做到这一点似乎很容易引起错误。这也许就是 C++ 选择不支持它的原因。 在编译 C 和 C++ 时我会添加 -Wshadow -Werror 所有 C++ 标准,在与 for 语句有关的部分中,都有一个子句要求 for-init-statement (@987654326) 中的所有变量的范围@ 在您的示例中)以扩展到 for 语句的末尾。这可以防止在 for 语句中再次声明这些变量。所有 C 标准都没有等效子句(在与 for 语句相关的部分或其他任何地方) - 它允许(不阻止)在 for 循环的块中重新声明变量。一种或另一种方法是否具有优势 - 这是一个见仁见智的问题。 @AntonioVázquezBlanco:我很确定这在所有 C 标准中是一致的,在所有 C++ 标准中都是一致的,但在 C 和 C++ 之间是不同的。 C 和 C++ 之间的这种变化是可能的,因为它是在 C++ 标准化的早期引入的 我认为这只是由于语言发展的历史。有时,有人想“嘿,如果我们可以在 for 语句中声明新变量,就在我们需要它们的地方,并且它们的范围以语句结束,这样以后就不会意外地使用它们,那就太好了。”然后人们开始使用它。但是在循环中声明相同的名称没有限制,有时人们会意外地这样做,即使他们不想这样做,也会将声明隐藏在 for 中。所以C++添加了禁止重新声明的规则…… 【参考方案1】:

就标准而言,for 循环范围在 C 和 C++ 中的定义确实不同。在 C 中,它们的定义如下:

6.8.5.3 for 语句

声明

for (clause-1 ; expression-2 ; expression-3 ) 语句

行为如下:...

没有具体提及statement 中变量声明的限制。循环的顶层描述(标准中的“迭代语句”)指定:

迭代语句是一个块,其范围是一个严格的子集 其封闭块的范围。循环体也是一个块,其 范围是迭代语句范围的严格子集。

正如您在问题中暗示的那样,代码如下:

for (int i = 0; i < 10; ++i)
    int i = 5;

未声明新块的地方(注意重新声明周围缺少 )- 不是有效代码。


而在 C++ 中,有一个对循环变量重新声明的特定引用:

8.6 迭代语句指定循环 ... 如果在 init-statement 或 for-range-declaration 在最外层重新声明 子语句块,程序格式错误


由于它与基本原理有关 - 可能 C++ 只是将限制添加为对语言语义的改进,实际上以这种方式重新声明变量通常是一个错误。

可以说,这个限制在 C 中也是合适的 - 但是将这个限制添加到 C 标准中会破坏与现有代码的向后兼容性并且不太可能发生。

【讨论】:

以上是关于C++中“for”循环的范围规则与C中不同? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

C++ STL应用与实现26: 如何使用std::for_each以及基于范围的for循环 (since C++11)

C++范围for

c++、java、C#之间的for循环初始化变量范围

C++基于范围的for循环详解

喵呜:C++基础系列:auto关键字(C++11)基于范围的for循环(C++11)指针空值nullptr(C++11)

喵呜:C++基础系列:auto关键字(C++11)基于范围的for循环(C++11)指针空值nullptr(C++11)