2

I found some behavior with extern and static (internal) variables that I find quite weird.

Here is an example:

/* file a.c */
#include <stdio.h>

/* variable with static linkage */
static int x = 24;

int f() {
        /* variable with extern linkage */
        extern int x; 
        return x;
}

int main() {
        printf("%d\n", f());
        return 0;
}

-

/* file x.c */
/* define symbol `x` to be an `int` equal to 100 */
int x = 100;

I compile this program using:

$ cc a.c x.c -o a

I then run my program and get this output:

$ ./a
24

Why does this program output 24 and not 100?

wefwefa3
  • 3,722
  • 2
  • 26
  • 50
  • 3
    "static" isn't a linkage. The linkages are "external", "internal" and "none". – Kerrek SB Feb 06 '16 at 22:44
  • Possible duplicate of [Can local and register variables be declared extern?](http://stackoverflow.com/questions/14335742/can-local-and-register-variables-be-declared-extern) – Chris Beck Feb 06 '16 at 22:56
  • It's probably related to the way linkers work. Linker will always search for a definition of a given identifier in a current compilation unit before searching in others. You can also for example redefine some `C` library functions in your code and use them instead of standard ones. – Arkadiusz Drabczyk Feb 06 '16 at 22:57
  • 1
    Not saying this question is an exact dupe of that question, but one of the answers there goes in exhaustive detail into the standard and I believe it explains your observed behavior along the way. – Chris Beck Feb 06 '16 at 22:59
  • to put it in one sentence. local scope masks global scope. – user3629249 Feb 06 '16 at 23:45
  • @user3629249 that doesn't help with the question , which is why `extern int x;` finds `static int x` in the same unit and not `int x` in the other unit. – M.M Feb 07 '16 at 00:03
  • The answer exactly tells why, local variables take precedence over external variables. – user3629249 Feb 07 '16 at 00:58
  • `static int x = 24;` is not a local variable – M.M Feb 07 '16 at 01:05
  • The reason I write `static` instead of `internal` in the title was because `static` is something that I think more C programmers can relate to. I will keep it this way but you are correct with that the proper definition is `internal`. – wefwefa3 Feb 07 '16 at 08:51
  • @ChrisBeck This is not a duplicate of [this](http://stackoverflow.com/questions/14335742/can-local-and-register-variables-be-declared-extern). That question asks if local variables (that is stack and register variables) can be declared with `extern`. Here I am confused at what happens when you mix `extern` with `static`. – wefwefa3 Feb 07 '16 at 08:56
  • *static int x = 24 is not a local variable.* I did not reference function local variables (on the stack) but rather file local variables, In general, use `extern` when referencing something in another file and `static` when you want the variable to only be visible within the one file. – user3629249 Feb 07 '16 at 22:06

1 Answers1

5

Quoting from link

The following table identifies the linkage assigned to an object that is declared twice in a single translation unit. The column designates the first declaration, and the row designates the redeclaration.

Table to resolve conflicting linkages

Also from the standard section 6.2.2:

For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible, if the prior declaration specifies internal or external linkage, the linkage of the identifier at the later declaration is the same as the linkage specified at the prior declaration. If no prior declaration is visible, or if the prior declaration specifies no linkage, then the identifier has external linkage.

Hence the file a.c has all its external linkages resolved internally. Your code has defined x as static first and then as external in the translation unit a.c. Hence linkage is internal from the table above. So it prints 24.

Community
  • 1
  • 1
  • The table, while nice in spirit, confuses specifiers and linkage. `extern` and `static` are specifiers, but "no linkage" is a linkage. A declaration at namespace scope doesn't require any specifier but results in external or internal, but not no, linkage. – Kerrek SB Feb 06 '16 at 23:26
  • That link (and the table) is just wrong -- read the standard section you quote! If *A PRIOR DECLARATION OF THAT IDENTIFIER IS VISIBLE*, the `extern` is effectively ignored and the linkage type is determined by that prior visible declaration. – Chris Dodd Feb 07 '16 at 02:01
  • Isn't the last column of table also saying same thing as the standard I quoted? Am I missing something? – Ravichandra Sutrave Feb 07 '16 at 04:24