10

I am trying a small example to know about the static external variable and its uses. The static variable is of local scope and the external variable is of global scope.

static5.c

#include<stdio.h>
#include "static5.h"
static int m = 25;
int main(){
 func(10);
 return 0;
}

static5.h

#include<stdio.h>
int func(val){
 extern int m;
 m = m + val;
 printf("\n value is : %d \n",m);
}

gcc static5.c static5.h

o/p :

static5.c:3: error: static declaration of m follows non-static declaration
static5.h:3: note: previous declaration of m was here

EDITED

The correct program :

a.c:
#include<stdio.h>
#include "a1_1.h"
int main(){
 func(20);
 return 0;
}

a1.h:
static int i = 20;

a1_1.h:
#include "a1.h"
int func(val){
 extern int i;
 i = i + val;
 printf("\n i : %d \n",i);
}

This works fine perfectly fine. But this is compiled into a single compilation unit. Hence could able to access the static variable . Across the compilation unit we cannot use the static variable by using the extern variable.

Angus
  • 12,133
  • 29
  • 96
  • 151

4 Answers4

20

static has a very simple logic to it. If a variable is static, it means that it is a global variable, but it's scope is limited to where it is defined (i.e. only visible there). For example:

  • Outside a function: global variable but visible only within the file (actually, the compilation unit)
  • Inside a function: global variable but visible only within the function
  • (C++) Inside a class: global variable but visible only to the class

Now let's see what the C11 standard says regarding static and extern (emphasis mine):

6.2.2.3

If the declaration of a file scope identifier for an object or a function contains the storage-class specifier static, the identifier has internal linkage.

6.2.2.4

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.

6.2.2.7

If, within a translation unit, the same identifier appears with both internal and external linkage, the behavior is undefined.

So the standard says that first, if you have:

static int m;
extern int m;

then the second declaration (with extern) would regard the first one and in the end m would still be static.

However, in any other case, if there are declarations with both internal and external linkage, the behavior is undefined. This actually leaves us with only one option:

extern int m;
static int m;

i.e., extern declaration before static declaration. gcc was nice enough to give you error in this case of undefined behavior.

Community
  • 1
  • 1
Shahbaz
  • 46,337
  • 19
  • 116
  • 182
  • Hi, thanks for the nice explanation. But it baffles me that one would use `static` and `extern` together - it seems to speak to me "I want var a to associate with this file only (static) and I would expose it (extern) to all other files". It sounds conflicting. Am I correct with my understanding? If not, when would one would need to use both `static` and `extern` together? Thanks in advance. – Unheilig Apr 18 '15 at 06:10
  • @unheilig, true in your personal project, but it's not without merit in general. In the case of `static` before `extern`, imagine a library with the usual header files with extern function declarations. You could override some of those functions by declaring them as `static` before including the header. A sort of compile-time-enabled `valgrind` for example could be possible with this method. – Shahbaz Apr 18 '15 at 09:08
  • The other way is probably problematic because after the `extern` declaration, the compiler would generate code to be linked to that declaration, but later you say it was supposed to be `static`, so the compiler has to go back and fix the previous code. Since C compilers are single-pass, this is annoying at best. – Shahbaz Apr 18 '15 at 09:09
17

Remember this (quoting Eli Bendersky):

  • A static variable inside a function keeps its value between invocations.
  • A static global variable or a function is "seen" only in the file it's declared in

In your code, static int m = 25; means that m's scope is limited only to that file, that is, it is only visible inside static5.c and nowhere else.

If you would like to make use of m outside of static5.c make sure to remove the keyword static from the declaration of the variable.

For a more canonical explanation, along with an example, see this answer by Eli Bendersky

EDIT: (according to Klas' recommendation) **The actual scope is a compilation unit, not the source file. The compilation unit is the way the file looks after the preprocessor step

Community
  • 1
  • 1
NlightNFotis
  • 9,559
  • 5
  • 43
  • 66
  • 5
    The scope is compilation unit, not source file. The compilation unit is the way the file looks after the preprocessor step, and then func is in the same file. – Klas Lindbäck Jun 11 '13 at 10:28
  • @KlasLindbäck Thanks for the remark! I am gonna update my answer. – NlightNFotis Jun 11 '13 at 10:29
  • @NlightNFortis: Its one compilation unit only. I do gcc static5.c and static5.h. the code is compiled into single compilation unit. But still I got the error. – Angus Jun 11 '13 at 10:39
  • @Angus Yes the *preprocessor* changes the `include "static5.h"` inside static5.c with the source code of that file, so the error messages denote that when it comes the time for the actual compilation, the compiler finds a `non-static` declaration of m (the one inside the func inside `static5.h`) before it finds the static one (inside the `static5.c` file). – NlightNFotis Jun 11 '13 at 10:43
  • Where is a static variable inside a function actually stored ? Is it also stored in `.data` like a regular global variable? – ljk321 Nov 03 '15 at 10:55
3

The problem is exactly as stated in the error message. m is declared a normal int but is later defined as a static int.

extern tells the compiler/linker to look for the variable in the global table of variables.

static (outside a functon) tells the compiler to exclude the variable from the global table of variables.

Do you see the conflict?

To fix the problem, either remove the static keyword from the definition or move the definition above the inclusion of static5.h.

It should be noted that the way you have designed your files is not considered best practice. Include files don't usually contain functions.

Klas Lindbäck
  • 33,105
  • 5
  • 57
  • 82
  • I thought so at first too, but the standard is more flexible on that. If the `static` declaration comes before the `extern` declaration, it is perfectly ok. See my answer for references. Only problem is if the `extern` declaration comes first. – Shahbaz Jun 11 '13 at 12:22
  • @Shahbaz Thanks for the clarification. I was not sure whether the extern declaration would be erroneous of simply superfluous. – Klas Lindbäck Jun 11 '13 at 13:03
2

remove the keyword static while declaring m and the errors will be removed and you will be able to get the answer as 50. The static keyword makes the scope to restrict within the file.

Santhosh Pai
  • 2,535
  • 8
  • 28
  • 49