I am wondering if the C snippet below, in which the definition of f fails to repeat that f is of static linkage, is correct:
static int f(int);
int f(int x) { return x; }
Clang does not emit any warning for it. I read clause 6.7.1 of the C11 standard without finding the answer to my question.
It is possible to imagine more questions along the same vein, for instance t1.c and t2.c below, and it would be nice if an answer was general enough to apply to some of these, but I am only really concerned about the first example above.
~ $ cat t1.c
static int f(int);
int f(int);
int f(int x) { return x; }
~ $ clang -c -std=c99 -pedantic t1.c
~ $ nm t1.o
warning: /Applications/Xcode.app/…/bin/nm: no name list
~ $ cat t2.c
int f(int);
static int f(int);
int f(int x) { return x; }
~ $ clang -c -std=c99 -pedantic t2.c
t2.c:3:12: error: static declaration of 'f' follows non-static declaration
static int f(int);
^
t2.c:1:5: note: previous declaration is here
int f(int);
^
1 error generated.
The rules for linkage are a little confusing, and it is different for functions and objects. In short, the rules are as follows:
The first declaration determines the linkage.
static means internal linkage.
extern means linkage as already declared, if none is declared, external.
If neither of them is given, it’s the same as extern for functions, and external linkage for object identifiers (with a definition in the same translation unit).
So, this is valid:
static int f(int); // Linkage of f is internal.
int f(int); // Same as next line.
extern int f(int); // Linkage as declared before, thus internal.
int f(int x) { return x; }
This, on the other hand, is undefined behaviour (cf. C11 (n1570) 6.2.2 p7):
int f(int); // Same as if extern was given, no declaration visible,
// so linkage is external.
static int f(int); // UB, already declared with external linkage.
int f(int x) { return x; } // Would be fine if either of the above
// declarations was removed.
Most of this is covered in C11 6.2.2. From the N1570 draft:
(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. 30)
(4) For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible31), 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.
(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.
30) A function declaration can contain the storage-class specifier static only if it is at file scope; see 6.7.1.
31) As specified in 6.2.1, the later declaration might hide the prior declaration.
According to C11, 6.2.2, 7 they are all undefined behaviours.
If, within a translation unit, the same identifier appears with both
internal and external linkage, the behavior is undefined.
A function is also an identifier and a function by default (without any qualifier like static) has external linkage.
C11, 6.2.1 Scopes of identifiers
1 An identifier can denote an object; a function; a tag or a member of a structure, union, or enumeration; a
typedef name; a label name; a macro name; or a macro parameter. The
same identifier can denote different entities at different points in
the program. A member of an enumeration is called an enumeration
constant. Macro names and macro parameters are not considered further
here, because prior to the semantic phase of program translation any
occurrences of macro names in the source file are replaced by the
preprocessing token sequences that constitute their macro definitions.
Related
Consider the following example program:
#include <stdio.h>
static int n = 123;
extern int n;
int main(void) { printf("n is %d\n", n); return 0; }
It compiles successfully with gcc -std=c99 -pedantic myprog.c. n has static linkage according to C99 § 6.2.2 Linkages of identifiers, part 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.
Now remove extern:
#include <stdio.h>
static int n = 123;
int n;
int main(void) { printf("n is %d\n", n); return 0; }
This program does not compile. GCC gives this error:
myprog.c:4:5: error: non-static declaration of ‘n’ follows static declaration
4 | int n;
| ^
myprog.c:3:12: note: previous definition of ‘n’ was here
3 | static int n = 123;
|
Why does this error occur? I thought that the int n; in the second program is supposed to be equivalent to extern int n;. From the C99 standard, § 6.2.2 Linkages of identifiers, part 5:
If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external.
You've already found the relevant parts in the standard. §4 says that if you declare it extern and there's already an internal linkage variable declared, then the linkage of your extern turns internal too - so it will refer to the same variable, just as if you had written static int n; twice.
These rules are kind of muddy and oddball features like this are obsolete. I don't know the historical reasons why it's there in the first place.
6.11.2 Linkages of identifiers
Declaring an identifier with internal linkage at file scope without the static storage class specifier is an obsolescent feature.
In the latter case you specify no linkage so it's a tentative definition. As per your quoted part in §5, it gets external linkage and then you get a naming collision with the internal linkage identifier in the same translation unit, hence the compiler error.
The following compiles fine, using static only during declaration of function:
#include <stdio.h>
static int a();
int a(){
return 5;
}
int main(){
printf("%d\n", a());
return 0;
}
As a side note, same behaviour as above happens with inline functions, i.e only the declaration could have the keyword.
However the following fails, doing the same but on a variable:
#include <stdio.h>
static int a;
int a = 5;
int main(){
printf("%d\n", a);
return 0;
}
Getting thew error:
non-static declaration of 'a' follows static declaration.
What is with the difference?
This quote from the C Standard shows the difference )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.
So a function looks like it has the implicit storage specifier extern (but it does not mean that it has the external linkage opposite to an object identifier that in this case has the external linkage).
Now according to the following quote
4 For an identifier declared with the storage-class specifier extern
in a scope in which a prior declaration of that identifier is
visible,31) 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
So the function has the internal linkage due to its initial declaration with the storage specifier static.
As for the identifier of a variable then
7 If, within a translation unit, the same identifier appears with both
internal and external linkage, the behavior is undefined.
The resume from the above cited quotes is the following. If a function has no explicitly specified storage class specifier extern then its linkage is determined by a prior function declaration (if such a declaration exists). As for an identifier of object then in this case it has the external linkage. And if there is a prior declaration of the identifier with the internal linkage then the behavior is undefined.
According to C standard:
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.
In my example we have three separate declarations with each identifier having a different linkage.So why doesn't this work?
static int a; //a_Internal
int main(void) {
int a; //a_Local
{
extern int a; //a_External
}
return 0;
}
Error:
In function 'main':
Line 9: error: variable previously declared 'static' redeclared 'extern'
Why does compiler insist that I'm redeclaring instead of trying to access external object in another file?
Valid C++ example for reference:
static void f();
static int i = 0; // #1
void g() {
extern void f(); // internal linkage
int i; // #2 i has no linkage
{
extern void f(); // internal linkage
extern int i; // #3 external linkage
}
}
Both Clang and VC seem to be okay with my C example; only some versions of GCC (not all) produce the aforementioned error.
§6.2.2, 7 says:
If, within a translation unit, the same identifier appears with both
internal and external linkage, the behavior is undefined.
So, your program has undefined behaviour.
§6.2.2, 4 says that
extern int a; //a_External
has external linkage because the prior declaration visible in the scope int a; //a_Local has no linkage. But
static int a; //a_Internal
declares a with internal linkage. Hence, it's undefined per §6.2.2, 7.
The compiler is giving this error because inside the a_External scope, a_Internal is still accessible, thus you are redeclaring a_Internal from static to extern in a_External because of the name collision of a. This problem can be solved by using different variable names, for example:
static int a1; //a_Internal
int main(void) {
int a2; //a_Local
{
extern int a3; //a_External
}
return 0;
}
C standard says:
In the set of translation units each declaration of a particular
identifier with external linkage denotes the same entity (object or
function). Within one translation unit, each declaration of an
identifier with internal linkage denotes the same entity.
In the set of translation units we cannot have multiple distinct external entities with the same name, so the types of each declaration that denotes that single external entity should agree. We can check if types agree within one translation unit, this is done at compile-time. We cannot check if types agree between different translation units neither at compile-time nor at link-time.
For an identifier declared with the storage-class specifier extern in
a scope in which a prior declaration of that identifier is visible,31)
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.
static int a; //a_Internal
int main(void) {
int a; //No linkage
{
extern int a; //a_External
}
return 0;
}
Here the previous declaration of identifier a has no linkage, so extern int a has external linkage. It means that we have to define int a in another translation unit. However GCC decided to reject this code with variable previously declared static redeclared 'extern' error, probably because we have undefined behavior according to C standard.
I thought externs were to share variables between compilation units. Why does the below code work ? and how does it work exactly ? Is this good practice ?
#include <stdio.h>
int x = 50;
int main(void){
int x = 10;
printf("Value of local x is %d\n", x);
{
extern int x;
printf("Value of global x is %d\n", x);
}
return 0;
}
Prints out :
Value of local x is 10
Value of global x is 50
When you use the extern keyword, the linker finds a symbol with a matching name in object files / libraries / archives. Symbols are, simply speaking, functions and global variables (local variables are just some space on the stack), thus the linker can do it's magic here.
About it being a good practice - global variables in general are not considered a good practice since they cause spaghetti code and 'pollute' the symbols pool.
You might (or might not) be interested to know that GCC (4.9.1) and clang (Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn)) have divergent views on the acceptability of the following code, which is a minor adaptation of the code in the question:
#include <stdio.h>
static int x = 50; // static instead of no storage class specifier
int main(void)
{
int x = 10;
printf("Value of local x is %d\n", x);
{
extern int x;
printf("Value of global x is %d\n", x);
}
return 0;
}
I called the source file ext.c.
$ clang -O3 -g -std=c11 -Wall -Wextra -Werror ext.c -o ext
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror ext.c -o ext
ext.c: In function ‘main’:
ext.c:9:20: error: variable previously declared ‘static’ redeclared ‘extern’
extern int x;
^
ext.c: At top level:
ext.c:2:12: error: ‘x’ defined but not used [-Werror=unused-variable]
static int x = 50;
^
cc1: all warnings being treated as errors
$
The problem is to determine which compiler is correct because they can't both be right unless the program is exhibiting undefined behaviour — which, if you bother to read to the end, will turn out to be the case.
The relevant section of the C11 standard is:
6.2.2 Linkages of identifiers
¶1 An identifier declared in different scopes or in the same scope more than once can be
made to refer to the same object or function by a process called linkage.29) There are
three kinds of linkage: external, internal, and none.
¶2 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.
¶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.30)
This means that the first or outermost declaration (definition) of x in the code above 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,31) 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.
This paragraph needs detailed deconstruction below.
¶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.
In the original code in the question, the second sentence says that the first declaration (definition) of x has external linkage.
¶6 The following identifiers have no linkage: an identifier declared to be anything other than
an object or a function; an identifier declared to be a function parameter; a block scope
identifier for an object declared without the storage-class specifier extern.
The x declared (defined) at the start of the function is 'a block scope identifier …' and therefore has no linkage.
¶7 If, within a translation unit, the same identifier appears with both internal and external
linkage, the behavior is undefined.
29) There is no linkage between different identifiers.
30) A function declaration can contain the storage-class specifier static only if it is at file scope; see
6.7.1.
31) As specified in 6.2.1, the later declaration might hide the prior declaration.
Dissecting paragraph 4
Paragraph 4 is the key one here. Restating it and annotating it:
4 For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible,31)
The third or innermost declaration of x is declared in a scope in which a prior declaration of that identifier is visible — the int x = 10; declaration is visible (the static int x = 50; declaration is invisible, having been shadowed by the visible declaration). The footnote refers to §6.2.1 Scopes of identifiers but I don't think ithat says anything surprising (however, I'll quote the relevant paragraphs — ¶2 and ¶4 — if you think that's necessary).
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.
This does not apply; the prior declaration specifies neither internal nor external linkage.
If no prior declaration is visible, or if the prior declaration specifies no linkage,
There is a prior declaration that's visible, and that declaration specifies no linkage.
then the identifier has external linkage.
So, the innermost x has external linkage, the outermost x has internal linkage, and as a consequence, paragraph 7 says the resulting behaviour is undefined. That means that both compilers are correct; if the behaviour is undefined, any behaviour is correct — and different compilers are allowed to have divergent views on what is correct, and GCC and clang exhibit divergent views. On the whole, GCC's "it is a problem that should be reported" view is safer for the programmer.
In the original code, the outermost x has external linkage, the innermost x also has external linkage, and as a consequence paragraph 7 does not apply, and the innermost declaration of x refers to the outermost declaration (and definition) of x.
Apart from showing that interpreting the standard is hard work, this whole answer (diatribe) also shows that using multiple compilers (if possible on different platforms) is a good idea. It gives you the maximum chance of finding problems. Depending on a single compiler leaves you vulnerable to missing problems that another compiler might spot.
Consider these examples:
static int a;
extern int a; //OK -- what linkage does the a have now?
static int a;
int a; //ERROR
extern int a;
static int a; //ERROR
int a;
static int a; //ERROR
extern int a;
int a; //OK as expected
int a;
extern int a; //OK as expected
Why was it OK in the first example but not in the second?
As far as file-scope variables (global-scope) are concerned, these have external linkage and a static duration when no keyword is specified.
Thank you
AFAIK, linkage and storage duration for functions is a bit different.
EDIT:
I've tried compiling using gcc 4.5.2 -Wall -pedantic --std=c99
More on: http://c-faq.com/decl/static.jd.html You can see that the 1st example works there too but 2nd doesn't. However, I don't see what makes them so different.
The answer to your first question is found in §6.2.2 of the C standard:
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.
So the linkage of a is internal.
For your second question, the second sentence of the immediately following paragraph is apropos:
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.
Because a is an object, not a function, the declaration int a; with no storage-class specifier gives a external linkage. The same section then has this to say:
7 If, within a translation unit, the same identifier appears with both
internal and external linkage, the behavior is undefined.
Since, in your second example, a appears with both internal and external linkage, this paragraph is triggered. One (particularly helpful) manifestation of undefined behaviour is the error that your compiler is producing.
All of your examples can be understood by these rules:
int a; always declares a with external linkage;
static int a; always declares a with internal linkage;
extern int a; declares a with whatever linkage it already had, or external linkage if it had none;
Two declarations of a in the same scope with different linkage give undefined behaviour.
I got same error when I forget "{" instead of ";" at the end of a declaration.
Example:
extern void *HASHMP_get(struct HASHMP_wf_s *hmwf_ptr, Uint8 *key);
extern void *HASHMP_remove(struct HASHMP_wf_s *hmwf_ptr, Uint8 *key) {
extern Uint16 HASHMP_clear(struct HASHMP_wf_s *hmwf_ptr);