75

Possible Duplicate:
Static vs global

I'm confused about the differences between global and static global variables. If static means that this variable is global only for the same file then why in two different files same name cause a name collisions?

Can someone explain this?

Community
  • 1
  • 1
MoonBun
  • 4,322
  • 3
  • 37
  • 69
  • 3
    If both variables are declared static in different files, it shouldn't cause a name collision. I just performed a quick test and it works as expected. If it doesn't work for you, please post the code where it doesn't work as you expect, what you expect and what you get, and what compiler you're using. – Kevin Oct 20 '11 at 14:15

2 Answers2

119

Global variables (not static) are there when you create the .o file available to the linker for use in other files. Therefore, if you have two files like this, you get name collision on a:

a.c:

#include <stdio.h>

int a;

int compute(void);

int main()
{
    a = 1;
    printf("%d %d\n", a, compute());
    return 0;
}

b.c:

int a;

int compute(void)
{
    a = 0;
    return a;
}

because the linker doesn't know which of the global as to use.

However, when you define static globals, you are telling the compiler to keep the variable only for that file and don't let the linker know about it. So if you add static (in the definition of a) to the two sample codes I wrote, you won't get name collisions simply because the linker doesn't even know there is an a in either of the files:

a.c:

#include <stdio.h>

static int a;

int compute(void);

int main()
{
    a = 1;
    printf("%d %d\n", a, compute());
    return 0;
}

b.c:

static int a;

int compute(void)
{
    a = 0;
    return a;
}

This means that each file works with its own a without knowing about the other ones.


As a side note, it's ok to have one of them static and the other not as long as they are in different files. If two declarations are in the same file (read translation unit), one static and one extern, see this answer.

Community
  • 1
  • 1
Shahbaz
  • 46,337
  • 19
  • 116
  • 182
  • What about declaring one static and the other not? – Kissaki Aug 30 '13 at 09:51
  • 1
    @kissaki, if those declarations are in different files, it's ok. The file that has the static declaration would use that static variable which is invisible to other files. All the files that have the non-static variable declaration, would use the shared global variable. – Shahbaz Aug 30 '13 at 19:29
  • If those two declarations, one static and one extern, are written in the same file (read translation unit), see [this answer](http://stackoverflow.com/a/17043698/912144). – Shahbaz Aug 30 '13 at 19:30
  • How do you compile `a.c` and `b.c` ? – ljk321 Nov 03 '15 at 10:43
  • @skyline75489, are you asking how C files are compiled in general? That depends on your compiler. That's a very basic question, try to search online. – Shahbaz Nov 06 '15 at 20:22
  • @Shahbaz I'm using `gcc -o test.out a.c b.c`. It actually works. The name collision error does not show up as expected. – ljk321 Nov 07 '15 at 01:56
  • @skyline75489, I just took a look at it, and you are right. This seems to be beyond the realm of the minimum that C says about linking. If you have `int a;`, in Linux with gcc 5.2.1, I get the variable specified as "Common symbol" (you can use `nm` to see this info. `nm` tags it with `C`). `int a = 0;` gets placed in BSS (`nm` tags it with `B`) and `int a = something_else;` gets placed in "Initialized data" (`nm` tags it with `D`). Apparently, the GNU `ld` rules are that symbols in `C` get linked with symbols in `B` and `D`. I can't tell whether other compilers and linkers show this behavior. – Shahbaz Nov 07 '15 at 20:34
  • In the above example, if you initialize both `a`s, you will get the link error. – Shahbaz Nov 07 '15 at 20:35
  • And I noticed that without `static` it compiles and the output is `0, 0`. With `static` the output would be `1, 0`. This `0, 0` is not correct. Yet `gcc` does not give any warning, even with `-Wall`. Should this be considered as a bug or something? – ljk321 Nov 08 '15 at 00:03
  • 1
    `0, 0` is not wrong. Without `static`, the two `a`s are linked together, so they are the same `a`. In the `printf`, you are printing `a` and the result of `compute()` which also modifies `a`. C says that the order of evaluation of function parameters is unspecified. Which means that the compiler could choose to either first calculate `a`, then `compute()`, or first `compute()` then `a`. In the first case, you would get `1, 0` and in the second case you would get `0, 0`. Both are valid and in fact its a programming error to rely on either behavior. – Shahbaz Nov 08 '15 at 15:46
  • And just FYI, with a language like `C`, where you can have variable number of arguments (with `...`) it in fact makes a lot of sense to evaluate arguments from right to left, which means first `compute()`, and then `a`. This is consistent with the `0, 0` output that you see. – Shahbaz Nov 08 '15 at 15:47
9

A name that's static in each file should not cause name collisions. If you're seeing that, please post (short) demo code showing it, along with the exact compiler you're using so we can properly verify the code and assuming it's correct, proper vilify the compiler.

Just FWIW, the preferred method in C++ is to use an anonymous namespace instead:

namespace { 
    int not_a_static_variable;
}

In all honesty, no I can't point to a lot of objective advantage to that though...

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • 1
    `In all honesty, no I can't point to a lot of objective advantage to that though...`... Maybe this topic can help in some way : [Why unnamed namespace is a“ superior” alternative to static?](http://stackoverflow.com/questions/4977252/why-unnamed-namespace-is-a-superior-alternative-to-static) – Nawaz Oct 20 '11 at 14:24
  • 5
    C++11 removes the deprecation of static objects, so these days neither method is particularly "preferred". – Mike Seymour Oct 20 '11 at 14:38
  • @MikeSeymour: That is also true. – Nawaz Oct 20 '11 at 14:46
  • @MikeSeymour: Removal of the official deprecation doesn't mean it isn't preferred. As I attempted to imply, there are even a *few* reasons to prefer it, just not a lot (the only one I've ever encountered in real code was wanting to use something as a template parameter, and at least personally, I only ever remember that arising once or maybe twice). – Jerry Coffin Oct 20 '11 at 14:49