在C中重新声明for循环中的变量

时间:2017-11-30 05:58:31

标签: c gcc declaration

我在GCC编译器上使用gcc prog.c -Wall -Wextra -std=gnu11 -pedantic命令编译了以下程序。我想知道,它没有任何警告或错误,工作正常。

#include <stdio.h>

int main(void)
{
    for (int i = 0; i == 0;  i++) 
    {        
        printf("%d\n", i);
        long int i = 1; // Why doesn't redeclaration error?
        printf("%ld\n", i);
    }
}

为什么编译器不会生成重新声明变量i错误?

5 个答案:

答案 0 :(得分:6)

在C语言中,statement的范围嵌套在for循环init-statement的范围内。

根据Cppreference

  

在C ++中,init-statement的范围和范围   语句是同一个,在C中statement的范围是嵌套的   在init-statement 范围内。

根据stmt

  

for语句

for ( for-init-statement conditionopt ; expressionopt ) statement
     

相当于

{
    for-init-statement
    while ( condition ) {
            statement
            expression ;
      }
} 
     

除了在for-init-statement中声明的名称与条件中声明的名称相同的声明区域,   除了继续声明(不包括在另一个声明中)   迭代语句)将在重新评估之前执行表达式   条件。

答案 1 :(得分:6)

从标准§6.8.5.5(N1570

  

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

强调增加

答案 2 :(得分:2)

您必须设置-Wshadow以获取有关阴影变量的警告。 C中允许可变阴影。

但这是一个边缘案例。在for构造的头部中声明的var不在括号之外,因为它在构造之后没有范围。

不等于

int i;
for( i = 0; …)
{ … }
// is is still in scope but wouldn't if declared in the head of for

但是,它也不在括号内。

for( i = 0; …)
{ 
  int i; // this would be strange, because i is used before it is declared.
  … 
}

代码的最佳近似替代是:

{
  int i;
  for( i = 0; …)
  {
  … 
  }
}  // i loses scope

所以这不是重新声明,而是循环体内的阴影声明。

答案 3 :(得分:0)

  

Why compiler doesn't generate redeclaration variable i error?

来自C Standards#6.2.1p4 Scopes of identifiers

  

每个其他标识符的范围由其声明的位置(在声明符或类型说明符中)确定。如果声明标识符的声明符或类型说明符出现在任何块或参数列表之外,则标识符具有文件范围,该范围终止于转换单元的末尾。如果声明标识符的声明符或类型说明符出现在块内或函数定义中的参数声明列表中,则标识符具有块作用域,该作用域终止于关联块的末尾。如果声明标识符的声明符或类型说明符出现在函数原型(不是函数定义的一部分)的参数声明列表中,则标识符具有函数原型作用域,该作用域终止于函数声明符的末尾。如果标识符指定同一名称空间中的两个不同实体,则范围可能会重叠。如果是这样,一个实体(内部范围)的范围将严格地在另一个实体(外部范围)的范围之前结束。 在内部范围内,标识符指定在内部范围内声明的实体;在外部范围内声明的实体在内部范围内隐藏(并且不可见)。

来自C standards#6.8.5p5 Iteration statements

  

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

所以,在这段代码中:

for (int i = 0; i == 0;  i++)
{
    printf("%d\n", i);
    long int i = 1; // Why doesn't redeclaration error?
    printf("%ld\n", i);
}

名称为i的标识符范围重叠,在此名称空间中,i中声明的for (int i = 0; i == 0; i++)具有外部范围,并且在循环体long int i = 1;具有内部范围

在循环体内,在此声明之后:

long int i = 1;

外部作用域中声明的i 不可见printf()打印内部作用域i可见的值1 }。

此行为也称为变量阴影,当在某个范围内声明的变量与在外部作用域中声明的变量具有相同名称时,会发生此行为。

C语言允许变量阴影,这就是编译器不会为此引发任何错误的原因。但是,在gcc编译器中,如果您使用-Wshadow选项,则会收到一条警告消息 - declaration shadows a local variable

答案 4 :(得分:0)

为了进一步验证,我在visual studio 2008中检查了prog.c文件中的代码。我发现编译器确实在行中给出了错误(int i = 0; i == 0; i ++)。编译器期望i的声明在程序本身的开头。此行为对于C文件是正确的。如果声明被移动到程序的开头,则没有预期的错误。所有与范围相关的问题都已解决。

如果我将此代码作为prog.cpp文件尝试,则编译器确实会为重新声明提供错误。这也是一种预期的行为。

所以我得出结论这与gcc编译器有关,用于编译/构建exe的任何标志/参数都会导致gcc编译器的这种行为。

rsp可以发布make文件详细信息以进一步验证吗?