tags:

views:

222

answers:

5

I just discovered a bug where the code looked something like this:

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

This compiles, but it's weird that I am allowed to define two variables within the same function, but the compiler appears to scope them differently.

If this were the case, how do I differentiate the inner foo with the outer one? How did the compiler know that in the free before my second declaration, I was trying to free the outer foo, but then when I redeclared the inner foo, it didn't give me an error?

Thanks for any info. This is probably a pretty obvious, newbie question.

+3  A: 

The scope of your second 'foo' starts at its declaration and continues until the end of the block it is declared in. When you call free(foo) it is acting on the first 'foo' because the second foo has not been declared yet.

After declaring the second 'foo' there is no way to access the outer 'foo'. You have essentially masked the name.

Trent
I figured as much, but how would I differentiate within the block of my if statement?
Sam
There is no way to access the external variable after you've hidden it. The solution is to use a different name for one of the foo variables. It's bad practice to hide names like this, and it's almost always going to cause trouble. It's also trivial to rename one of them.
Eclipse
I agree, Josh. When I was coding this segment up, it wasn't my intention to do any hiding. I had a typo (or brain slip) and simply tacked on that char * to the beginning of my malloc without really thinking about it. It compiled, I checked it in, people immediately began encountering problems. A quick GDB session revealed this problem, which was why I asked the question.
Sam
Yeah - I've done that before. It's unfortunate really that this is allowed at all. I can't think of a situation where having name hiding be a compile error wouldn't be a good thing.
Eclipse
+3  A: 

This is not an error, it is possible to declare variables with the same names in different scopes.

The compiler knows that the foo inside the free function is the outer one because at that point it is the only foo of the program.

After the declaration of the second foo you should use

::foo = ...

to access the outer foo, (edit) if the outer foo is declared as global (outside any function).

fbinder
So then if I start nesting foos deeper (I know, never do this, but the question is purely academic at this point), would I just increase the number of semicolons?
Sam
Which compiler/language allows ::foo to access the outer foo? I am not familiar with that in standard C or C++. Not sure about objective-C but I don't think it's allowed there either.
Trent
It only works if foo is a global variable, not if foo is a local variable.
Eclipse
Yeah, I may have to uncheck it, I just wrote a small test C++ program, got a ::a undeclared. Maybe Josh has a point...
Sam
Yes, my mistake. I edited my answer so it is correct now.
fbinder
@Josh Thanks for the clarification. 'foo' in the example clearly cannot be a global variable - I didn't expand on that in my early comment.
Trent
+2  A: 

Hi

This because of scoping and symbol tables.

The example you have here is more wired than normal scoping (and i would strongly advice not to use such constructs). But the explanation is that the compiler updates the symbol table at the point you declare the new variable, until then the symbol table lookup falls trough to the outer scope.

As you can see with this example the address of the pointer changes:

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

    void *var = NULL;

    std::cout << "From inner scope: " << &var << std::endl;
}
Fionn
+12  A: 

C++ defines a new scope for variables every time you use { }. Take a look at this example here.

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;
}

When you run this, you get:

 hello
 world 
 global 
 hello

When you open a new scope and declare a variable with the same name as a variable in an enclosing scope, you hide the variable in the outer scope as long as you remain in the current scope. Once you leave the inner scope, the outer variable becomes visible again. If the outer variable happens to be a globabl variable, you can access with the global namespace ::foo. If the outer variable is a class variable, you can use className::foo. If the outer variable is just a local variable, there is no way to access it until you leave the scope where you declared the variable that hid it.

I haven't used C in a while, so C99 will likely be different, but in the older C, there is no way to access a hidden name.

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;
}

When you run this, you get:

 world 
 hello
Eclipse
This answer is very C++ specific. The question is also tagged with C and objective-C.
Trent
True. Is there a C solution? The C solution would basically cover the Objective-C solution as well. Is it simply impossible to access something once you've hidden the scope?
Sam
There isn't a C solution. In C, you can't access a hidden variable from an enclosing scope.
Eclipse
@Josh: There is C solution - see my post.
qrdl
+5  A: 

As other posters wrote, you shadow the variable when declare the variable with the same name within inner scope, e.g. function or block.

But there is a way to access shadowed global non-static variable in 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
}

I made some dummy blocks because with pre-C99 compilers you cannot declare the variable in the middle of the block.

qrdl
+1 Cool, I hadn't thought of that. Of course you still can't access both foos at the same time.
Eclipse
Yeah, that's the main problem - either global or local, but not both.
qrdl