C++ 在循环中重新声明for循环变量时出错

C++ 在循环中重新声明for循环变量时出错,c++,c,for-loop,C++,C,For Loop,考虑一下C程序的这个片段: for(int i = 0; i < 5; i++) { int i = 10; // <- Note the local variable printf("%d", i); } 但是如果我用C++编写一个类似的循环: for(int i = 0; i < 5; i++) { int i = 10; std::cout << i; } for(int i=0;i这是因为C和C++语

考虑一下C程序的这个片段:

for(int i = 0; i < 5; i++)
{
    int i = 10;  // <- Note the local variable

    printf("%d", i); 
}    
但是如果我用C++编写一个类似的循环:

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

     std::cout << i; 
}
for(int i=0;i<5;i++)
{
int i=10;

STD::CUT< P>这是因为C和C++语言在< <代码>嵌套的范围内对变量的变量声明有不同的规则,对于循环:

  • C++
    i
    放在循环体的范围内,因此第二个
    int i=10
    是一个被禁止的重新声明
  • C
    允许在
    循环的
    范围内重新声明;最里面的变量“wins”
这是一个,和一个的演示

在主体内打开嵌套范围修复编译错误():

for(int i=0;i!=5;i++){
{
int i=10;

CUT

不像C,C++有规则,
C++11-§6.5.3/1:

用于
语句的

for ( for-init-statement conditionopt ; expressionopt ) statement 除了在for init语句中声明的名称与在条件[…]中声明的名称位于相同的声明区域

这意味着init语句
范围与
语句
的范围相同*,下面的代码将导致错误

for(int i = 0; i < 5; i++){
     int i = 10;    // Invalid. 
     // ...
}


建议阅读:n3337:6.5.1 while语句/p(2)。在§9.5.1和§9.5.3节的c++17草案(n4659)中可以找到相同的参考。

这不是重新声明。

仔细看这个

for(int i = 0; i < 7; i++)
{
    printf("i = %d\n", i);
    int i = 5;
    printf("new i = %d\n", i);
}
显然,有两种不同的
i

较新的
i
具有更局部的作用域

这是一个bug吗?

没有

目的是什么?

如果不允许,维护大型项目可能会非常困难,因为您会经常遇到命名冲突

一般来说,在不同的作用域中给不同的变量取相同的名称被认为是非常糟糕的做法,但您应该尽可能避免这样做

为什么没有警告消息?

使用
gcc文件\u name.c-Wshadow
进行编译



<> > >编辑:强>也可以通过将它们声明为循环来本地锁定原始声明的变量。< /强>

这是C还是C++?问题不是那么坏。它是变量的范围和C和C++中的行为方式不同。“在C++中,init语句的范围和语句的范围是相同的,在C中,语句的范围嵌套在init语句的范围内:…“请参见引用下面的示例:@Bob_uu_uu你的编辑使问题获得+9:)让我们保持原样。问题的内容非常清楚。投票重新打开。有一个疑问
(int i=0;i@achal它会产生重新声明错误,因为在C++中<<代码> < /COD> >循环有一个用于主体的变量和在头部中声明的变量。实际上只有旧的C允许,这是因为循环迭代器属于全局范围。Ofc,可以在下面的范围内声明相同的ID。C99。一点也不正确。@AndriyTylychko谈到TurboC++、QuickC(不是C++)和之前的ofc,现在人们说“不是这样的。”"因为clang和gcc的实现方式不同,如果使用适当的-std标志,它们的行为也不同。这是标准文本中定义可疑的结果,在高于循环体的范围内定义init语句,然后在注释中添加了:但不能使用相同的标识符。注意,C89不允许声明for()头中的变量。但是编译器已经有了。for()的混乱循环、初始值设定项和虚拟关键字都是历史问题。N3242是C++11之前的草案;建议阅读的内容应该是最新的标准和/或最新的draft@M.M最新的你是说N471草案?我认为C++标准语言实际上不把这个问题的例子标记为错误。实际上有两个层次分开。从循环体中包含的
int i=10;
中删除for init语句的
int i=0
。首先,在“相当于”之后的替换文本在语句周围引入了额外的大括号,而words中声明的异常并不引用,因为它只涉及for init语句和条件(我的斜体)处于相同的声明级别;它根本没有提到循环体。(…)其次,在示例中,语句(循环体)实际上是一个复合语句(即,它的最外层标记是大括号),这些大括号保留在替换文本中,因此具体地说,替换文本变为
{int i=0;而(iI)在我写评论之前,我读过这些章节;你为什么认为我没有读过?顺便说一下,我在6.5中也读过“如果迭代语句中的子语句是单个语句而不是复合语句,就好像它被重写为包含原始语句的复合语句”这意味着您可以有效地获得一对大括号,即使您编写了一个没有大括号的循环体(但这在示例中不适用),并且6.3“复合语句定义了一个块范围”,没有任何例外或修改。因此每个循环体都是一个单独的块范围
for ( for-init-statement conditionopt ; expressionopt ) statement
{
    for-init-statement 
    while ( condition ) {
        statement 
        expression ;
    } 
}
for(int i = 0; i < 5; i++){
     int i = 10;    // Invalid. 
     // ...
}
for(int i = 0; i < 5; i++){
    {
         int i = 10;    // Valid. 
         // ...
    }
}
for(int i = 0; i < 7; i++)
{
    printf("i = %d\n", i);
    int i = 5;
    printf("new i = %d\n", i);
}
i = 0
new i = 5
i = 1
new i = 5
i = 2
new i = 5
i = 3
new i = 5
i = 4
new i = 5
i = 5
new i = 5
i = 6
new i = 5