views:

105

answers:

3

I'm a little fuzzy on how variable access between .cpp files works. For instance:

main.cpp

int main()
{
    int a = i;
    return 0;
}

main2.cpp

int i;

This generates a compiler error on main.cpp, telling me there is no in i in existence. What difference then, does the "static" keyword do in this context? (I tried Googling for it, but most of the "static keyword" info pages talk about classes & functions)

main2.cpp

static int i;

Is it the same? Does it prevent extern int i being used to access i elsewhere? How does the use of anonymous namespaces differ in how variables are handled?

main2.cpp

namespace
{
    int i;
}

To sum up:

  • Can variables be accessed between .cpp files? (aside from extern keyword)
  • How does the static keyword on a global variable affect things?
  • How do anonymous namespaces affect things differently?
+1  A: 

All global variables have some kind of linkage. extern linkage is required to name the same variable in different contexts between different files.

extern is the default. If you actually use extern in a variable declaration, it's treated as a reference to another file. Omit any linkage specifier to actually create the variable; this must happen in only one file.

extern int i; // i exists somewhere in some .cpp file.
int i; // ah! this is the file it exists in. 
       // (Although nothing special about that.)

static applied to a global (at namespace scope) makes it local to the file. You get the same effect from a private namespace, so static outside function or class scope is deprecated. Many still use it though.

The exception to the rule of static meaning file-local is in classes and inline functions. Class static members should more properly be called extern since the semantics are identical. It's ugly and confusing, but I guess Bjarne just wanted to eliminate extern as a keyword.

Inline functions can have the same definition among multiple .cpp files, so when one creates a static variable, the variable definition is shared as well.

Potatoswatter
I guess it's technically true that in C++ you have to "actually create" a variable only once, but every compiler I've ever used has been perfectly fine with merging extern-less "int i;" in two or more files. (Left over from C, I suppose, where those are "tentative definitions" and merging is obligatory.)
Zack
@Zack: Every compiler I've used was totally anal about it. The main practical issue is that they may be initialized to different values.
Potatoswatter
IME they only get anal if more than one extern-less declaration has an initializer.
Zack
A: 
  • yes, for example you can use static class variables
  • it makes variable local and persistent to compilation unit
  • anonymous namespace prevents collision between symbols. it is as if you create uniquely named namespace manually
aaa
+1  A: 

In your first example, main2.cpp defines a global variable i, which could have been accessed by main.cpp if an extern declaration of i had appeared in that file. (Normally that extern declaration would come from a header file.) You got a compiler error because i had never been declared in main.cpp, which means the compiler assumes there is no such variable.

In your second example, main2.cpp defines a file scope variable i. File scope variables are distinct from globals, even if they happen to have the same name. If you had had an extern declaration of i in main.cpp in the second example, both files would have compiled successfully, but then you would have gotten a link error because no global variable i was defined.

If you renamed main2.cpp from the second example to main3.cpp, added an extern declaration of i to main.cpp, compiled all three and linked them all together, that would succeed; main.cpp and main2.cpp would share one variable named i, and main3.cpp would have its own entirely separate variable also named i.

This stuff is called linkage. Namespaces are almost entirely unrelated to linkage. However, the anonymous namespace is special. Defining a variable in an anonymous namespace is for all practical purposes the same as defining it with static -- it makes it a file scope variable. (If I remember correctly, there is a difference, but it only matters if you are doing complicated things with exported templates, and as exported templates are so little used that they're talking about deleting the feature from the C++ standard, you don't have to worry about it.)

The value of the anonymous namespace is that you can put a class definition inside it, and that makes all of the class's methods be file-local. (Only the class { ... } block has to be inside the namespace { ... } block to get this effect.) You can't do that any other way.

Zack