有趣的范围问题,解释?

时间:2009-05-27 22:04:20

标签: c++ c objective-c

我刚刚发现了一个代码如下所示的错误:

char *foo = malloc(SOME_NUM * sizeof(char));
if (!processReturnsTrueOrFalse(foo)) {
    free(foo);
    char *foo = malloc(SOME_NUM * sizeof(char));
    // More stuff, whatever
}

这是编译,但我很可能在同一个函数中定义了两个变量,但是编译器看起来的范围不同。

如果是这种情况,我如何区分内部foo和外部foo?编译器是如何知道在我的第二次声明之前的免费中,我试图释放外部foo,但是当我重新声明内部foo时,它没有给我一个错误?

感谢您的任何信息。这可能是一个非常明显的新手问题。

5 个答案:

答案 0 :(得分:12)

每次使用{ }时,C ++都会为变量定义新范围。看看这个例子。

const char *foo = "global";

int main(int argc, char* argv[])
{
    const char *foo = "hello";

    {
        cout << foo << endl;
        const char *foo = "world";
        cout << foo << endl;
        cout << ::foo << endl;
    }
    cout << foo << endl;
}

当你运行它时,你得到:

 hello
 world 
 global 
 hello

当您打开一个新范围并声明一个与封闭范围中的变量同名的变量时,只要您保留在当前范围内,就会在外部范围中隐藏该变量。离开内部范围后,外部变量将再次可见。如果外部变量恰好是globabl变量,则可以使用全局名称空间::foo进行访问。如果外部变量是类变量,则可以使用className::foo。如果外部变量只是一个局部变量,那么在您离开声明隐藏它的变量的范围之前,无法访问它。

我暂时没有使用过C,所以C99可能会有所不同,但在较旧的C中,无法访问隐藏名称。

const char *foo = "global";

int main(int argc, char* argv[])
{
    const char *foo = "hello";

    {
        char *foo = "world";
        printf("%s\n", foo);
    }
    printf("%s\n", foo);
    return 0;
}

当你运行它时,你得到:

 world 
 hello

答案 1 :(得分:5)

正如其他海报写的那样,当你在内部范围内声明具有相同名称的变量时,你shadow变量,例如功能或阻止。

但是有一种方法可以在C中访问带阴影的全局非静态变量:

int foo = 1;                       // global

int bar(void) {

    printf ("%d", foo);            // print global
    {
        int foo = 2;               // global foo shadowed
        printf ("%d", foo);        // print local
        {
             extern int foo;       // local foo shadowed
             printf("%d", foo);    // print global
        }                          // global foo shadowed
        printf ("%d", foo);        // print local
    }                              // end of scope for local foo
}

我制作了一些虚拟块,因为使用C99之前的编译器,你无法在块的中间声明变量。

答案 2 :(得分:3)

你的第二个'foo'的范围从它的声明开始并一直持续到声明它的块的结尾。当你调用free(foo)时它会对第一个'foo'起作用,因为第二个foo没有已经宣布。

在声明第二个'foo'之后,无法访问外部'foo'。你基本上掩盖了这个名字。

答案 3 :(得分:3)

这不是错误,可以在不同的范围内声明具有相同名称的变量。

编译器知道free函数中的foo是外部函数,因为那时它是程序的唯一foo。

在宣布第二个foo之后你应该使用

::foo = ...

访问外部foo,(编辑)如果外部foo被声明为全局(在任何函数之外)。

答案 4 :(得分:2)

这是因为范围和符号表。

你在这里的例子比正常的范围更有线(我强烈建议不要使用这样的结构)。但解释是编译器在声明新变量时更新符号表,直到符号表查找落到外部范围。

正如您在此示例中所看到的,指针的地址会发生变化:

void *var = NULL;
{
    std::cout << "From outer scope: " << &var << std::endl;

    void *var = NULL;

    std::cout << "From inner scope: " << &var << std::endl;
}