为什么不给出重新声明错误?

时间:2014-11-10 11:57:34

标签: c++ c

我有这段代码 - http://ideone.com/8Q8XIo

#include <stdio.h>

int xyz = 10;
int main(void) {

    int xyz = 20;//line 2
    printf("%d",xyz);

    return 0;
}

我的问题是 - 为什么不给出重新声明错误?我知道第二次它在'main'函数的范围内。但我认为在'第2行'中只做xyz = 20就可以了,但不是int xyz = 20

5 个答案:

答案 0 :(得分:4)

C范围规则表示,当块内的声明命名已经可见的标识符时,新声明会暂时隐藏旧声明,并且标识符具有新含义
在块的末尾,标识符重新获得其旧的含义。

C11:6.2.1标识符的范围(p4):

  

[...]如果标识符指定同名的两个不同实体   空间,范围可能重叠。如果是这样,一个实体的范围(内部范围)将结束   严格地在另一个实体的范围之前(外部范围)。 在内部范围内,   identifier指定在内部作用域中声明的实体;在外部宣布的实体   范围隐藏(并且在内部范围内不可见)

答案 1 :(得分:4)

根据C标准(6.2.1标识符范围)

  
      
  1. ...在内部范围内,标识符指定声明的实体   在内在范围内;在外部作用域中声明的实体是隐藏的   (并且在内部范围内不可见)。
  2.   

在您的示例中,第一个声明的标识符

int xyz = 10;

有文件范围。第二个声明的标识符

int xyz = 20;//line 2

具有包含在文件范围内的块范围。也就是说,块作用域是相对于文件作用域的内部作用域。第二个声明的标识符隐藏块范围内的第一个声明的标识符。

同样适用于C ++。只有C ++具有名称空间并使用限定名称,您可以访问隐藏的变量。例如

#include <iostream>

int xyz = 10;

int main() {

    int xyz = 20;//line 2

    std::cout << "xyz = " << xyz << ", ::xyz = " << ::xyz << std::endl;

    return 0;
}

::之前的xyz表示全局命名空间。

考虑到您还可以在函数声明中使用相同的名称作为函数参数声明。例如

void f( int xyz );

在这种情况下,此标识符具有函数原型范围。你甚至可以声明一个与例如

同名的标签

在C

xyz:;
int xyz = 20;

或在C ++中

xyz:
int xyz = 20;

同样在C标签中有自己的命名空间。所以这个声明在C

中有效
xyz:;

struct xyz
{
   int xyz;
};

int xyz = 20;

答案 2 :(得分:2)

  

为什么不给出重新声明错误?

因为它不是重新声明。您正在声明一个新的局部变量。由于它与全局范围中的名称相同,因此它隐藏那个,但那就是它。这是完全合法的C.

答案 3 :(得分:1)

它没有给出重新声明错误,因为它们位于不同的范围内。第一个声明在全局范围内,第二个声明在本地范围内(仅在main中有效)。

答案 4 :(得分:0)

  

为什么不给出重新声明错误?

因为(正如其他人所说)虽然这是重新声明,但只要两个变量在不同的范围内,它就不是错误的情况。

差异:

int f() {
    int x = 0;
    int x = 1; // same scope, this will not compile (redeclaration error)
}

int g() {
    int x = 0;
    {
        int x = 1; // inner scope, no conflict at all
        std::cout << x << "\n"; // print 1
    }
    std::cout << x << "\n"; // print 0
}