Share a variable between two files in C - c

I'm trying to understand on how to link two files with a variable. I know that the standard way is through extern keyword as shown below.
File 1
#include<stdio.h>
int i;
void func1();
int main()
{
i = 10;
func1();
printf("i value with method 1: %d\n", i);
}
File 2
extern int i;
void func1()
{
i = i+1;
}
Compile and execute => gcc *.c ./a.out
Output=> i value with method 1: 11
One thing I found is through headers as shown below:
common.h
#ifndef __COMMON_H
#define __COMMON_H
int i;
#endif
File 1
#include<stdio.h>
#include"common.h"
int main()
{
i = 10;
func1();
printf("i value with method 2: %d\n", i);
}
File 2
#include"common.h"
void func1()
{
i = i+1;
}
Compile and execute => gcc *.c ./a.out
Output=> i value with method 2: 11
My doubt is, How method2 works?

At file scope, int i; is a special kind of declaration called a tentative definition. In spite of its name, it is not a definition. However, it can cause a definition to be created.
A clean way to declare and define an object that is used in multiple translation units is to declare it with extern in a header that is included in each unit that uses the object by name:
extern int i;
and to define the object in one translation unit:
int i = 0;
At file scope, int i = 0; is a definition; the initialization with = 0 makes it a regular definition instead of a tentative definition.
Ideally, all source code would use clean declarations and definitions. However, C was not completely planned and designed in advance. It developed through experiments and different people in different places implementing things differently. When the C committee standardized C, they had to deal with different practices and implementations. One common practice was that of declarations such as int i; in multiple units that were intended to create a single i. (This behavior was inherited from FORTRAN, which had common objects as a similar feature.)
To accommodate this, the committee described int i; at file scope as a special kind of declaration, a tentative definition. If there is a regular definition in the same translation unit that defines the same identifier, the tentative definition acts as a plain declaration, not a definition. If there is no regular definition, the compiler (or other part of C implementation) creates a definition for the identifier as if it had been initialized with zero.
The C standard leaves reconciling of multiple tentative definitions to each C implementation; it does not define the behavior when int i; is used in multiple translation units. Prior to version 10, the default behavior of GCC was to use the “common symbol” behavior; multiple tentative definitions would be reconciled to a single definition when linking. (To support this, the compiler marks tentative definitions differently from regular definitions when creating object modules, so the linker knows which is which.) In version 10, the default changed, and GCC now treats the definitions resulting from tentative definitions as regular symbols instead of common symbols.
This is why you will see some people report they get an error when linking sources with tentative definitions while you and others do not. It is simply a matter of which version of which compiler and linker they used.
You can explicitly request either behavior with the GCC switch -fcommon for the common symbol behavior or -fno-common for the regular symbol behavior.
Generally, you should use the clean method above; declare identifiers with extern in headers, and put exactly one definition in each identifier in one source file.

Related

C - Globally defined vars in different files displaying external linkage without extern modifier

Thoroughly confused. I'm frustrated because I think it's important to know precisely how scope and linkage work, but I've been seeing conflicting info about extern and my compiler/linker is contradicting what I've read.
----------main.c--------------
int int1;
void main()
{ int1=6;
printf("\nMain - int1 = %4d", int1);
blippy();
printf("\nMain - int1 = %4d", int1);
return;
}
-------------second.c-------------
int int1;
void blippy()
{ printf("\nSecond - int1 = %4d", int1);
int1++;
return ;
}
Output is:
Main - int1 = 6
Second - int1 = 6
Main - int1 = 7
as if both instances of int1 pointed to one variable with external linkage. I would have expected the compiler to either throw a multiple definition error or treat them as static. I'm using Codeblocks, and I don't know if it's doing anything presumptous behind the scenes.
Largely for historic reasons, int int1; is neither a plain declaration nor a plain definition. It is a tentative definition. If there is no regular definition of int1 in the translation unit (the source file being compiled, including all the files it includes), and there is only one definition of it in the whole program, the tentative definition will act as a regular definition.
However, if you have tentative definitions (without regular definitions) of the same identifier in multiple translation units, the behavior is not defined by the C standard. Some compilers, including GCC until recently, allow multiple tentative definitions and allow the linker to coalesce them into a single definition. Starting with version 10, GCC does not do this and allows the linker to treat them as multiple definitions, unless requested otherwise by a switch, -fcommon.
You can make int int1; into a regular definition by providing an initializer, int int1 = 0;.
Some additional information is here and here.

Explanation of tentative definitions in C [duplicate]

This question already has answers here:
Tentative definitions in C and linking
(3 answers)
Closed 8 years ago.
Let's say I have two source files: main.c and a.c:
main.c:
#include <stdio.h>
int a;
int i;
int i;
int main(void)
{
printf("a = %d\n", a);
printf("i = %d\n", i);
return 0;
}
a.c:
int a;
Then, according to latest C99 draft 6.9.2 External object definitions p. 2 (emphasis mine):
A declaration of an identifier for an object that has file scope
without an initializer, and without a storage-class specifier or with
the storage-class specifier static, constitutes a tentative
definition. If a translation unit contains one or more tentative
definitions for an identifier, and the translation unit contains no
external definition for that identifier, then the behavior is exactly
as if the translation unit contains a file scope declaration of that
identifier, with the composite type as of the end of the translation
unit, with an initializer equal to 0.
Compilation (no warnings given):
gcc -g -std=c99 -pedantic-errors -Wall -Wextra main.c a.c
I understand that for i variable there two are tentative definitions and since main.c does not have "true" external definition they are merged into such one. What about a ? Do I state correctly, that tentative definitions are not "shared" between multiple source files (i.e. translation units) ?
Your program is erroneous: it defines the same external name more than once. The GNU tool chain follows a relaxed linkage model which does not flag this as an error; it merges the multiple definitions. However, that is effectively a language extension. Strictly conforming ISO C programs cannot define a name more than once.
The notion of a "tentative definition" is purely syntactic, within one translation unit. At the end of a translation unit, any definitions which are still tentative are "cemented" as definitions.
The reason int i; is called "tentative" is that it is "weak" in a sense. It can be overridden by a later definition. If, by the end of the translation unit, it isn't then it turns into int i = 0.
So for instance this is valid:
int i; /* might become int i = 0 */
int i = 42; /* i is now defined; the tentative definition is replaced */
In this situation, i is understood to be defined once, not twice. The translated unit contains a single definition of i.

C the same global variable defined in different files

I am reading this code from here(in Chinese). There is one piece of code about testing global variable in C. The variable a has been defined in the file t.h which has been included twice. In file foo.c defined a struct b with some value and a main function. In main.c file, defined two variables without initialized.
/* t.h */
#ifndef _H_
#define _H_
int a;
#endif
/* foo.c */
#include <stdio.h>
#include "t.h"
struct {
char a;
int b;
} b = { 2, 4 };
int main();
void foo()
{
printf("foo:\t(&a)=0x%08x\n\t(&b)=0x%08x\n
\tsizeof(b)=%d\n\tb.a=%d\n\tb.b=%d\n\tmain:0x%08x\n",
&a, &b, sizeof b, b.a, b.b, main);
}
/* main.c */
#include <stdio.h>
#include "t.h"
int b;
int c;
int main()
{
foo();
printf("main:\t(&a)=0x%08x\n\t(&b)=0x%08x\n
\t(&c)=0x%08x\n\tsize(b)=%d\n\tb=%d\n\tc=%d\n",
&a, &b, &c, sizeof b, b, c);
return 0;
}
After using Ubuntu GCC 4.4.3 compiling, the result is like this below:
foo: (&a)=0x0804a024
(&b)=0x0804a014
sizeof(b)=8
b.a=2
b.b=4
main:0x080483e4
main: (&a)=0x0804a024
(&b)=0x0804a014
(&c)=0x0804a028
size(b)=4
b=2
c=0
Variable a and b has the same address in two function, but the size of b has changed. I can't understand how it worked!
You are violating C's "one definition rule", and the result is undefined behavior. The "one definition rule" is not formally stated in the standard as such. We are looking at objects in different source files (aka, translation units), so we concerned with "external definitions". The "one external definition" semantic is spelled out (C11 6.9 p5):
An external definition is an external declaration that is also a definition of a function (other than an inline definition) or an object. If an identifier declared with external linkage is used in an expression (other than as part of the operand of a sizeof or _Alignof operator whose result is an integer constant), somewhere in the entire program there shall be exactly one external definition for the identifier; otherwise, there shall be no more than one.
Which basically means you are only allowed to define an object at most once. (The otherwise clause allows you to not define an external object at all if it is never used anywhere in the program.)
Note that you have two external definitions for b. One is the structure that you initialize in foo.c, and the other is the tentative definition in main.c, (C11 6.9.2 p1-2):
If the declaration of an identifier for an object has file scope and an initializer, the
declaration is an external definition for the identifier.
A declaration of an identifier for an object that has file scope without an initializer, and without a storage-class specifier or with the storage-class specifier static, constitutes a tentative definition. If a translation unit contains one or more tentative definitions for an identifier, and the translation unit contains no external definition for that identifier, then the behavior is exactly as if the translation unit contains a file scope declaration of that identifier, with the composite type as of the end of the translation unit, with an initializer equal to 0.
So you have multiple definitions of b. However, there is another error, in that you have defined b with different types. First note that multiple declarations to the same object with external linkage is allowed. However, when the same name is used in two different source files, that name refers to the same object (C11 6.2.2 p2):
In the set of translation units and libraries that constitutes an entire program, each
declaration of a particular identifier with external linkage denotes the same object or
function.
C puts a strict limitation on declarations to the same object (C11 6.2.7 p2):
All declarations that refer to the same object or function shall have compatible type;
otherwise, the behavior is undefined.
Since the types for b in each of your source files do not actually match, the behavior is undefined. (What constitutes a compatible type is described in detail in all of C11 6.2.7, but it basically boils down to being that the types have to match.)
So you have two failings for b:
Multiple definitions.
Multiple declarations with incompatible types.
Technically, your declaration of int a in both of your source files also violates the "one definition rule". Note that a has external linkage (C11 6.2.2 p5):
If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external.
But, from the quote from C11 6.9.2 earlier, those int a tentative definitions are external definitions, and you are only allowed one of those from the quote from C11 6.9 at the top.
The usual disclaimers apply for undefined behavior. Anything can happen, and that would include the behavior you observed.
A common extension to C is to allow multiple external definitions, and is described in the C standard in the informative Annex J.5 (C11 J.5.11):
There may be more than one external definition for the identifier of an object, with or
without the explicit use of the keyword extern; if the definitions disagree, or more than one is initialized, the behavior is undefined (6.9.2).
(Emphasis is mine.) Since the definitions for a agree, there is no harm there, but the definitions for b do not agree. This extension explains why your compiler does not complain about the presence of multiple definitions. From the quote of C11 6.2.2, the linker will attempt to reconcile the multiple references to the same object.
Linkers typically use one of two models for reconciling multiple definitions of the same symbol in multiple translation units. These are the "Common Model" and the "Ref/Def Model". In the "Common Model", multiple objects with the same name are folded into a single object in a union style manner so that the object takes on the size of the largest definition. In the "Ref/Def Model", each external name must have exactly one definition.
The GNU toolchain uses the "Common Model" by default, and a "Relaxed Ref/Def Model", where it enforces a strictly one definition rule for a single translation unit, but does not complain about violations across multiple translation units.
The "Common Model" can be suppressed in the GNU compiler by using the -fno-common option. When I tested this on my system, it caused "Strict Ref/Def Model" behavior for code similar to yours:
$ cat a.c
#include <stdio.h>
int a;
struct { char a; int b; } b = { 2, 4 };
void foo () { printf("%zu\n", sizeof(b)); }
$ cat b.c
#include <stdio.h>
extern void foo();
int a, b;
int main () { printf("%zu\n", sizeof(b)); foo(); }
$ gcc -fno-common a.c b.c
/tmp/ccd4fSOL.o:(.bss+0x0): multiple definition of `a'
/tmp/ccMoQ72v.o:(.bss+0x0): first defined here
/tmp/ccd4fSOL.o:(.bss+0x4): multiple definition of `b'
/tmp/ccMoQ72v.o:(.data+0x0): first defined here
/usr/bin/ld: Warning: size of symbol `b' changed from 8 in /tmp/ccMoQ72v.o to 4 in /tmp/ccd4fSOL.o
collect2: ld returned 1 exit status
$
I personally feel the last warning issued by the linker should always be provided regardless of the resolution model for multiple object definitions, but that is neither here nor there.
References:
Unfortunately, I can't give you the link to my copy of the C11 Standard
What are extern variables in C?
The "Beginner's Guide to Linkers"
SAS Documentation on External Variable Models
Formally, it is illegal to define the same variable (or function) with external linkage more than once. So, from the formal point of view the behavior of your program is undefined.
Practically, allowing multiple definitions of the same variable with external linkage is a popular compiler extension (a common extension, mentioned as such in the language specification). However, in order to be used properly, each definition shall declare it with the same type. And no more than one definition shall include initializer.
Your case does not match the common extension description. Your code compiles as a side effect of that common extension, but its behavior is still undefined.
The piece of code seems to break the one-definition rule on purpose. It will invoke undefined behavior, don't do that.
About the global variable a: don't put definition of a global variable in a header file, since it will be included in multiple .c files, and leads to multiple definition. Just put declarations in the header and put the definition in one of the .c files.
In t.h:
extern int a;
In foo.c
int a;
About the global variable b: don't define it multiple times, use static to limit the variable in a file.
In foo.c:
static struct {
char a;
int b;
} b = { 2, 4 };
In main.c
static int b;
b has the same address because the linker decided to resolve the conflict for you.
sizeof shows different values because sizeof is evaluated at compile time. At this stage, the compiler only knows about one b (the one defined in the current file).
At the time foo is being compiled, the b that is in scope is the two ints vector {2, 4} or 8 bytes when an sizeof(int) is 4.
When main is compiled, b has just been redeclared as an int so a size of 4 makes sense. Also there is probably "padding bytes" added to the struct after "a" such that the next slot (the int) is aligned on 4 bytes boundary.
a and b have the same addresses because they occur at the same points in the file. The fact that b is a different size doesn't matter where the variable begins. If you added a variable c between a and b in one of the files, the address of the bs would differ.

How to group common data members/variables in c?

I am writing a code in C which has the following basic structure:
Part A: Starting/Init of the main module, calling of various sub-modules and final compliation of the results from the sub-modules.
Part B: Actual execution of the sub-modules.
Now, part A has its own main.c and main.h file
Part B has three modules:
sub1.c/sub1.h
sub2.c/sub2.h
sub3.c/sub3.h
There are a lot of common variables and functions that are used in the sub-modules.
I would like to have a common module which could be #included in all the sub-modules and all the common functions/variables be used. (common.c and common.h)
Now, for the common functions, I can declare them in common.h and then define in common.c and then they could directly be used in all the sub-modules.
But there are a lot of common data variables/members also which i want to 'common' out.
What would be the most efficient way of doing this, so that i could directly use them in all the sub-modules?
In c++, it could just be added to common.h and then could be used with any file that includes common.h but i believe that it is a little different in c.
Could someone please help explain the difference?
thanks
In C or C++:
Should go in a .h:
// declaration, means it's defined somewhere else
// can declare it as many times as you want
extern int yourVariable;
Every object (as in the intermediate file generated during the compilation process for a .c or .cpp file, not an object in OOP) that wants to use a variable needs to know about it (thus have a definition somewhere).
Should go in a .c/.cpp:
int yourVariable = 3; // definition, should only define it once
int yourVariable2; // also a definition
The extern keyword is optional for functions.
int square(int num); // function declaration (.h)
extern int square(int num); // same as above
int square(int num) { return num*num; } // function definition (.c)
In C++:
Should go in a .h:
// this is a declaration
class yourClass
{
int yourVariable;
}
Should go in a .cpp:
int yourClass::yourVariable = 3;
I could be wrong, but I'm not aware of difference between C and C++ in this regard (except that C++ has classes).

What is the difference between static and extern in C?

What is the difference between static and extern in C?
From http://wiki.answers.com/Q/What_is_the_difference_between_static_and_extern:
The static storage class is used to declare an identifier that is a local variable either to a function or a file and that exists and retains its value after control passes from where it was declared. This storage class has a duration that is permanent. A variable declared of this class retains its value from one call of the function to the next. The scope is local. A variable is known only by the function it is declared within or if declared globally in a file, it is known or seen only by the functions within that file. This storage class guarantees that declaration of the variable also initializes the variable to zero or all bits off.
The extern storage class is used to declare a global variable that will be known to the functions in a file and capable of being known to all functions in a program. This storage class has a duration that is permanent. Any variable of this class retains its value until changed by another assignment. The scope is global. A variable can be known or seen by all functions within a program.
static means a variable will be globally known only in this file. extern means a global variable defined in another file will also be known in this file, and is also used for accessing functions defined in other files.
A local variable defined in a function can also be declared as static. This causes the same behaviour as if it was defined as a global variable, but is only visible inside the function. This means you get a local variable whose storage is permanent and thus retain its value between calls to that function.
I'm no C expert so I might be wrong about this, but that's how I've understood static and extern. Hopefully someone more knowledgable will be able to provide you with a better answer.
EDIT: Corrected answer according to comment provided by JeremyP.
You can apply static to both variables and functions. There are two answers that discuss the behaviour of static and extern with respect to variables, but neither really covers functions. This is an attempt to rectify that deficiency.
TL;DR
Use static functions whenever possible.
Only declare external functions in headers.
Use the headers where the functions are defined and where the functions are used.
Don't declare functions inside other functions.
Don't exploit the GCC extension with function definitions nested inside other functions.
External functions
By default, functions in C are visible outside the translation unit (TU — basically the C source file and included headers) in which they are defined. Such functions can be called by name from any code that notifies the compiler that the function exists — usually by a declaration in a header.
For example, the header <stdio.h> makes visible declarations of functions such as printf(), fprintf(), scanf(), fscanf(), fopen(), fclose(), and so on. If a source file includes the header, it can call the functions. When the program is linked, the correct library must be specified to satisfy the function definition. Fortunately, the C compiler automatically provides the library that provides (most of) the functions in the standard C library (and it usually provides a lot more functions than just those). The 'most of' caveat applies because on many systems (Linux, for instance, but not macOS), if you use functions declared in the <math.h> header, you need to link with the maths library ('math' library if you're American), which usually is indicated by the option -lm on the linker command line.
Note that external functions should be declared in headers. Each external function should be declared in one header, but one header may declare many functions. The header should be used both in the TU where each function is defined and in each TU that uses the function. You should never need to write a declaration for a global function in a source file (as opposed to a header file) — there should be a header to declare the function and you should use that header to declare it.
Static functions
As an alternative to generally visible functions, you can make your own functions static. This means that the function cannot be called by name from outside the TU in which it is defined. It is a hidden function.
The primary advantage of static functions is hiding details which the outside world doesn't need to know about. It is a basic but powerful information hiding technique. You also know that if a function is static, you do not need to look for uses of the function outside the current TU, which can greatly simplify the search. However, if the functions are static, there can be multiple TUs which each contain a definition of a function with the same name — each TU has its own function, which may or may not do the same thing as a function with the same name in a different TU.
In my code, I qualify all functions except main() with the keyword static by default — unless there's a header that declares the function. If I subsequently need to use the function from elsewhere, it can be added to the appropriate header and the keyword static removed from its definition.
Declaring functions inside other functions
It is possible, but very inadvisable, to declare a function inside the scope of another function. Such declarations fly in the face of Agile Development maxims such as SPOT (Single Point of Truth) and DRY (Don't Repeat Yourself). They're also a maintenance liability.
However, you can, if you so desire, write code such as:
extern int processor(int x);
int processor(int x)
{
extern int subprocess(int);
int sum = 0;
for (int i = 0; i < x; i++)
sum += subprocess((x + 3) % 7);
return sum;
}
extern int subprocess(int y);
int subprocess(int y)
{
return (y * 13) % 37;
}
The declaration in processor() suffices for it to use subprocess(), but is otherwise unsatisfactory. The extern declaration before the definition is necessary if you use GCC compiler options such as:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes \
> -c process.c
process.c:12:5: error: no previous prototype for ‘subprocess’ [-Werror=missing-prototypes]
int subprocess(int y)
^~~~~~~~~~
cc1: all warnings being treated as errors
$
This is, I find, a good discipline, similar to what C++ enforces. It's another reason I make most functions static, and define the functions before they're used. The alternative is to declare static functions at the top of the file and then define them in whatever order seems appropriate. There are some merits to both techniques; I prefer to avoid the need to declare and define the same function in the file by defining before use.
Note that you cannot declare a static function within another function, and if you attempt to define a function such as subprocess() as a static function, the compiler gives an error:
process.c:12:16: error: static declaration of ‘subprocess’ follows non-static declaration
static int subprocess(int y)
^~~~~~~~~~
process.c:5:20: note: previous declaration of ‘subprocess’ was here
extern int subprocess(int);
^~~~~~~~~~
Since functions that are externally visible should be declared in a header, there is no need to declare them inside a function, so you should never run into this as a problem.
Again, the extern is not necessary in the function declaration inside the function; if omitted, it is assumed. This can lead to unexpected behaviour in novice programs here on SO — you sometimes find a function declaration where a call was intended.
With GCC, the option -Wnested-externs identifies nested extern declarations.
Called by name vs called by pointer
If you have a nervous disposition, stop reading now. This gets hairy!
The 'called by name' comment means that if you have a declaration such as:
extern int function(void);
you can write in your code:
int i = function();
and the compiler and linker will sort things out so that the function is called and the result used. The extern in the declaration of the function is optional but explicit. I normally use it in a header file to match the declaration of those rare global variables — where the extern is not optional but mandatory. Many people disagree with me on this; do as you wish (or must).
Now what about static functions?
Suppose the TU reveal.c defines a function static void hidden_function(int) { … }.
Then, in another TU openness.c, you cannot write :
hidden_function(i);
Only the TU that defines the hidden function can use it directly. However, if there's a function in reveal.c that returns a function pointer to the hidden_function(), then the code openness.c can call that other function (by name) to get a pointer to the hidden function.
reveal1.h
extern void (*(revealer(void)))(int);
Obviously, that's a function that takes no arguments and returns a pointer to a function that takes an int argument and returns no value. No; it isn't pretty. One of the times it makes sense to use typedef on pointers is with pointers to functions (reveal2.h):
typedef void (*HiddenFunctionType)(int);
extern HiddenFunctionType revealer(void);
There: much simpler to understand.
See Is it a good idea to typedef pointers for a general discussion on the subject of typedef and pointers; the short summary is "it isn't a good idea except perhaps with function pointers".
reveal1.c
#include <stdio.h>
#include "reveal1.h"
static void hidden_function(int x)
{
printf("%s:%s(): %d\n", __FILE__, __func__, x);
}
extern void (*(revealer(void)))(int)
{
return hidden_function;
}
Yes, it is legitimate (but very unusual) to define the function with an explicit extern — I very, very seldom do it, but here it emphasizes the role of extern and contrasts it with static. The hidden_function() can be returned by revealer(), and could be called by code inside reveal.c. You can remove the extern without changing the meaning of the program.
openness1.c
#include <stdio.h>
#include "reveal1.h"
int main(void)
{
void (*revelation)(int) = revealer();
printf("%s:%s: %d\n", __FILE__, __func__, __LINE__);
(*revelation)(37);
return 0;
}
This file cannot usefully contain a direct call by name to hidden_function() because it is hidden in the other TU. However, the revealer() function declared in reveal.h can be called by name and it returns a pointer to the hidden function, which can then be used.
reveal2.c
#include <stdio.h>
#include "reveal2.h"
static void hidden_function(int x)
{
printf("%s:%s(): %d\n", __FILE__, __func__, x);
}
extern HiddenFunctionType revealer(void)
{
return hidden_function;
}
openness2.c
#include <stdio.h>
#include "reveal2.h"
int main(void)
{
HiddenFunctionType revelation = revealer();
printf("%s:%s: %d\n", __FILE__, __func__, __LINE__);
(*revelation)(37);
return 0;
}
Sample outputs
Not the most exciting output in the world!
$ openness1
openness1.c:main: 7
reveal1.c:hidden_function(): 37
$ openness2
openness2.c:main: 7
reveal2.c:hidden_function(): 37
$
Both of these modifiers have something to do with memory allocation and linking of your code. The C standard[3] refers to them as storage-class specifiers. Using those allows you to specify when to allocate memory for your object and/or how to link it with the rest of the code. Let’s have look on what exactly is there to specify first.
Linking in C
There are three types of linkage – external, internal and none. Each declared object in your program (i.e. variable or function) has some kind of linkage – usually specified by the circumstances of the declaration. Linkage of an object says how is the object propagated through the whole program. Linkage can be modified by both keywords extern and static .
External Linkage
Objects with external linkage can be seen (and accessed) through the whole program across the modules. Anything you declare at file (or global) scope has external linkage by default. All global variables and all functions have external linkage by default.
Internal Linkage
Variables and functions with internal linkage are accessible only from one compilation unit – the one they were defined in. Objects with internal linkage are private to a single module.
None Linkage
None linkage makes the objects completely private to the scope they were defined in. As the name suggests, no linking is done. This applies to all local variables and function parameters, that are only accessible from within the function body, nowhere else.
Storage duration
Another area affected by these keywords is storage duration, i.e. the lifetime of the object through the program run time. There are two types of storage duration in C – static and automatic.
Objects with static storage duration are initialized on program startup and remain available through the whole runtime. All objects with external and internal linkage have also static storage duration. Automatic storage duration is default for objects with no linkage. These objects are allocated upon entry to the block in which they were defined and removed when the execution of the block is ended. Storage duration can be modified by the keyword static .
Static
There are two different uses of this keyword in the C language. In the first case, static modifies linkage of a variable or function. The ANSI standard states:
If the declaration of an identifier for an object or a function has
file scope and contains the storage-class specifier static , the
identifier has internal linkage.
This means if you use the static keyword on a file level (i.e. not in a function), it will change the object’s linkage to internal, making it private only for the file or more precisely, compilation unit.
/* This is file scope */
int one; /* External linkage. */
static int two; /* Internal linkage. */
/* External linkage. */
int f_one()
{
return one;
}
/* Internal linkage. */
static void f_two()
{
two = 2;
}
int main(void)
{
int three = 0; /* No linkage. */
one = 1;
f_two();
three = f_one() + two;
return 0;
}
The variable and function() will have internal linkage and won’t be visible from any other module.
The other use of static keyword in C is to specify storage duration. The keyword can be used to change automatic storage duration to static. A static variable inside a function is allocated only once (at program startup) and therefore it keeps its value between invocations
#include <stdio.h>
void foo()
{
int a = 10;
static int sa = 10;
a += 5;
sa += 5;
printf("a = %d, sa = %d\n", a, sa);
}
int main()
{
int i;
for (i = 0; i < 10; ++i)
foo();
}
The output will look like this:
a = 15, sa = 15
a = 15, sa = 20
a = 15, sa = 25
a = 15, sa = 30
a = 15, sa = 35
a = 15, sa = 40
a = 15, sa = 45
a = 15, sa = 50
a = 15, sa = 55
a = 15, sa = 60
Extern
The extern keyword denotes, that “this identifier is declared here, but is defined elsewhere”. In other words, you tell the compiler that some variable will be available, but its memory is allocated somewhere else. The thing is, where? Let’s have a look at the difference between declaration and definition of some object first. By declaring a variable, you say what type the variable is and what name it goes by later in your program. For instance you can do the following:
extern int i; /* Declaration. */
extern int i; /* Another declaration. */
The variable virtually doesn’t exist until you define it (i.e. allocate memory for it). The definition of a variable looks like this:
int i = 0; /* Definition. */
You can put as many declaration as you want into your program, but only one definition within one scope. Here is an example that comes from the C standard:
/* definition, external linkage */
int i1 = 1;
/* definition, internal linkage */
static int i2 = 2;
/* tentative definition, external linkage */
int i3;
/* valid tentative definition, refers to previous */
int i1;
/* valid tenative definition, refers to previous */
static int i2;
/* valid tentative definition, refers to previous */
int i3 = 3;
/* refers to previous, whose linkage is external */
extern int i1;
/* refers to previous, whose linkage is internal */
extern int i2;
/* refers to previous, whose linkage is external */
extern int i4;
int main(void) { return 0; }
This will compile without errors.
Summary
Remember that static – the storage-class specifier and static storage duration are two different things. Storage duration is a attribute of objects that in some cases can be modified by static , but the keyword has multiple uses.
Also the extern keyword and external linkage represent two different areas of interest. External linkage is an object attribute saying that it can be accessed from anywhere in the program. The keyword on the other hand denotes, that the object declared is not defined here, but someplace else.
Static
The static variables declared with the keyword static. The static variable initial value is 0. The static variables has block file scope scope.
Extern
A program in C, particularly when it is large, can be broken up into smaller programs. After compiling these, each program file can be joined together to form the large program. These small programs modules that combine together may need some variable that is used by all of them. In C, such a provision can be made by specifying these variables, accessible to all the small program modules, as an external storage class variable. These variables are global to all the small program modules that are formed as separate files. The keyword for declaring such global variables is extern.
Such a global variable is declared like any other variable in one of the program modules while the declaration of these variables is preceded with the keyword extern in all other combining program modules.
The program modules may also be a function or a block. These variables remain in existence as long as the program is in execution and their existence does not terminate upon the exit of a function or block or a program module from its state of execution. These variables are stored in the primary memory and their default value is zero.
Storage classes in C

Resources