In C99 6.7.1 it says
At most, one storage-class specifier may be given in the declaration
specifiers in a declaration
I know extern and static are both storage class specifiers but extern basically states to the compiler that the variable is declared elsewhere and worry about it later. extern and static to me are NOT mutually exclusive. It is very well possible that something could be extern and static.
Why can't we use extern and static together? Is there a good reason other than the standard simply says, no?
Well, static means Internal Linkage, extern means External Linkage.
Internal Linkage refers to everything only in scope of a Translation unit.
External Linkage refers to things that exist beyond a particular translation unit. In other words, accessable through the whole program.
So both are mutually exclusive.
"Static" outside all blocks means "internal linkage", "extern" means external linkage.
What should static extern mean? Internal external linkage???
Related
Is a function without a storage class specified in its declaration and definition :
void func(void); // declaration
void func(void) { // implementation
}
be equivalent to the function with extern storage class in its declaration and definition? :
extern void func(void); // declaration
extern void func(void) { // implementation
}
From the C Standard (6.2.2 Linkages of identifiers)
5 If the declaration of an identifier for a function has no
storage-class specifier, its linkage is determined exactly as if it
were declared with the storage-class specifier extern. If the
declaration of an identifier for an object has file scope and no
storage-class specifier, its linkage is external.
Identifiers for functions always have external linkage by default. Storage class is a separate issue.
Some rules about declarations are:
For declarations outside of functions, all identifiers have external linkage by default.
For declarations inside of functions, identifiers for functions have external linkage by default, and identifiers for objects have no linkage by default.
If the declaration includes static, the identifier has internal linkage.
By these rules, identifiers for functions have external linkage by default, have internal linkage if declared with static, and never have no linkage. There are additional rules for declarations which are not fully described here. The rules are a mishmash and a bit complicated due to the history of how C developed. Different C implementations did things in different ways, and the C standardization committee had to tie things together.
Functions do not have storage classes. Storage classes, or more properly, storage durations, are categories for the lifetimes of objects. extern and static are keywords called storage-class specifiers, which are different from storage classes (the same way “fox” and “dog” are words for animals but are not animals). Storage-class specifiers partly affect storage classes of objects, but they also affect linkages of identifiers and other things. Linkage of function identifiers is the issue here, not storage class. Linkage is the process by which declarations of identical identifiers in different places can be made to refer to the same object or function. Because of the complications in C history, the extern keyword causes external linkage for identifiers in a new declaration, and static causes internal linkage. (In a redeclaration of a visible identifier, extern does not change the prior linkage; in static int x; extern int x;, x still has internal linkage in the latter. As stated, the rules are complicated.)
I was reading a C reference about linkage (external, internal and none) and came across the following:
If, within a translation unit, the same identifier appears with both
internal and external linkage, the behavior is undefined.
I wanted to know how this undefined behavior can occur. Based on what I had read, a variable can have only one storage class. So it cannot be declared both static and extern at the same time.
So in what scenario can a variable have both internal and external linkage?
In this code:
extern int x;
static int x;
The first declaration says x has external linkage, and the second declaration says it has internal linkage.
Why the following doesn't compile?
...
extern int i;
static int i;
...
but if you reverse the order, it compiles fine.
...
static int i;
extern int i;
...
What is going on here?
This is specifically given as an example in the C++ standard when it's discussing the intricacies of declaring external or internal linkage. It's in section 7.1.1.7, which has this exert:
static int b ; // b has internal linkage
extern int b ; // b still has internal linkage
extern int d ; // d has external linkage
static int d ; // error: inconsistent linkage
Section 3.5.6 discusses how extern should behave in this case.
What's happening is this: static int i (in this case) is a definition, where the static indicates that i has internal linkage. When extern occurs after the static the compiler sees that the symbol already exists and accepts that it already has internal linkage and carries on. Which is why your second example compiles.
The extern on the other hand is a declaration, it implicitly states that the symbol has external linkage but doesn't actually create anything. Since there's no i in your first example the compiler registers i as having external linkage but when it gets to your static it finds the incompatible statement that it has internal linkage and gives an error.
In other words it's because declarations are 'softer' than definitions. For example, you could declare the same thing multiple times without error, but you can only define it once.
Whether this is the same in C, I do not know (but netcoder's answer below informs us that the C standard contains the same requirement).
For C, quoting the standard, in C11 6.2.2: Linkage of identifiers:
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.
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.
(emphasis-mine)
That explains the second example (i will have internal linkage). As for the first one, I'm pretty sure it's undefined behavior:
7) If, within a translation unit, the same identifier appears with both internal and external linkage, the behavior is undefined.
...because extern appears before the identifier is declared with internal linkage, 6.2.2/4 does not apply. As such, i has both internal and external linkage, so it's UB.
If the compiler issues a diagnostic, well lucky you I guess. It could compile both without errors and still be compliant to the standard.
C++:
7.1.1 Storage class specifiers [dcl.stc]
7) A name declared in a namespace scope without a storage-class-specifier has external linkage unless it has
internal linkage because of a previous declaration and provided it is not declared const. Objects declared
const and not explicitly declared extern have internal linkage.
So, the first one attempts to first gives i external linkage, and internal afterwards.
The second one gives it internal linkage first, and the second line doesn't attempt to give it external linkage because it was previously declared as internal.
8) The linkages implied by successive declarations for a given entity shall agree. That is, within a given scope,
each declaration declaring the same variable name or the same overloading of a function name shall imply
the same linkage. Each function in a given set of overloaded functions can have a different linkage, however.
[ Example:
[...]
static int b; // b has internal linkage
extern int b; // b still has internal linkage
[...]
extern int d; // d has external linkage
static int d; // error: inconsistent linkage
[...]
In Microsoft Visual Studio, both versions compile just fine.
On Gnu C++ you get an error.
I'm not sure which compiler is "correct". Either way, having both lines doesn't make much sense.
extern int i means that the integer i is defined in some other module (object file or library). This is a declaration. The compiler will not allocate storage the i in this object, but it will recognize the variable when you are using it somewhere else in the program.
int i tells the compiler to allocate storage for i. This is a definition. If other C++ (or C) files have int i, the linker will complain, that int i is defined twice.
static int i is similar to the above, with the extra functionality that i is local. It cannot be accessed from other module, even if they declare extern int i. People are using the keyword static (in this context) to keep i localize.
Hence having i both declared as being defined somewhere else, AND defined as static within the module seems like an error. Visual Studio is silent about it, and g++ is silent only in a specific order, but either way you just shouldn't have both lines in the same source code.
AFAIK, any declaration of a variable or a function in file scope has external linkage by default. static mean "it has internal linkage", extern -- "it maybe defined elsewhere", not "it has external linkage".
If so, why we need extern keyword? In other words, what is difference between int foo; and extern int foo; (file scope)?
The extern keyword is used primarily for variable declarations. When you forward-declare a function, the keyword is optional.
The keyword lets the compiler distinguish a forward declaration of a global variable from a definition of a variable:
extern double xyz; // Declares xyz without defining it
If you keep this declaration by itself and then use xyz in your code, you would trigger an "undefined symbol" error during the linking phase.
double xyz; // Declares and defines xyz
If you keep this declaration in a header file and use it from several C/C++ files, you would trigger a "multiple definitions" error during the linking phase.
The solution is to use extern in the header, and not use extern in exactly one C or C++ file.
As an illustration, compile the following program: (using cc -c program.c , or the equivalent)
extern char bogus[0x12345678] ;
Now remove the "extern" keyword, and compile again:
char bogus[0x12345678] ="1";
Run objdump (or the equivalent) on the two objects.
You will find that without the extern keyword space is actually allocated.
With the extern keyword the whole "bogus" thing is only a reference. You are saying to the compiler: "there must be a char bogus[xxx] somewhere, fix it up!"
Without the extern keyword you say: "I need space for a variable char bogus[xxx], give me that space!"
The confusing thing is that the actual allocation of memory for an object is postponed until link time: the compiler just adds a record to the object, informing the linker that an object should (or should not) be allocated. In all cases, the compiler at leasts will add the name (and size) of the object, so the linker/loader can fix it up.
C99 standard
I am going to repeat what others said but by quoting and interpreting the C99 N1256 draft.
First I confirm your assertion that external linkage is the default for file scope 6.2.2/5 "Linkages of identifiers":
If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external.
The confusion point is that extern does not only alter the linkage, but also weather an object declaration is a definition or not. This matters because 6.9/5 "External definitions" says there can only be one external definition:
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 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.
where "external definition" is defined by the grammar snippet:
translation-unit:
external-declaration
so it means a "file scope" top-level declaration.
Then 6.9.2/2 "External object definitions" says (object means "data of a variable"):
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:
extern int i;
is not a definition, because it does have a storage-class specifier: extern.
However:
int i;
does not have a storage-class specifier, so it is a tentative definition. And if there are no more external declarations for i, then we can add the initializer equal 0 = 0 implicitly:
int i = 0;
So if we had multiple int i; in different files, the linker should in theory blow up with multiple definitions.
GCC 4.8 does not comply however, and as an extension allows multiple int i; across different files as mentioned at: https://stackoverflow.com/a/3692486/895245 .
This is implemented in ELF with a common symbol, and this extension is so common that it is mentioned in the standard at J.5.11/5 Common extensions > Multiple external definitions:
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).
Another place where extern has an effect is in block-scope declarations, see: Can local and register variables be declared extern?
If there is an initializer for the object declaration, extern has no effect:
extern int i = 0;
equals
int i = 0;
Both are definitions.
For functions, extern seems to have no effect: Effects of the extern keyword on C functions as there is no analogous concept of tentative definition.
You can only define a variable once.
If multiple files use the same variable then the variable must be redundantly declared in each file. If you do a simple "int foo;" you'll get a duplicate definition error. Use "extern" to avoid a duplicate definition error. Extern is like saying to the compiler "hey, this variable exists but don't create it. it's defined somewhere else".
The build process in C is not "smart". It won't search through all the files to see if a variable exists. You must explicitly say that the variable exists in the current file, but at the same time avoid creating it twice.
Even in the same file, the build process is not very smart. It goes top to bottom and it won't recognize a function name if it is defined below the point of use, so you must declare it higher up.
see in one project source code i have seen belows declaration
static int *foo();
so it declare foo as static function returning pointer to int. So here i wana ask you whats the purpose of declaring function as static ?
The function's name isn't visible outside the translation unit (source file) in which it's declared, and won't conflict with another function foo in another source file.
In general, functions should probably be declared static unless you have a specific need to call it from another source file.
(Note that it's only the name that's not visible. It can still be called from anywhere in the program via a pointer.)
It prevents other translation units (.c files) from seeing the function. Keeps things clean and tidy. A function without static is extern by default (is visible to other modules).
From the C99 standard:
6.2.2 Linkages of identifiers
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.
and
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. Within one translation unit, each declaration of an identifier with internal
linkage denotes the same object or function. Each declaration of an identifier with no
linkage denotes a unique entity.
Declaring a function as static prevents other files from accessing it. In other words, it is only visible to the file it was declared in; a "local" function.
You could also relate static (function declaration keyword, not variable) in C as private in object-oriented languages.
See here for an example.
Marking a function or a global variable as static makes it invisible to the linker once the current translation unit is compiled into an object file.
In other words, it only has internal linkage within the current translation unit. When not using static or explicitly using the extern storage class specifier, the symbol has external linkage.