This question already has answers here:
Effects of the extern keyword on C functions
(10 answers)
Closed 7 years ago.
I was wondering if there is any difference if skip extern storage class specifier while declaring a function? Specifically, is there any difference between following two?
void foo ();
and
extern void foo();
is there any difference between following two?
Basically, no.
Each function declaration, is extern by default, (i.e., in absence of any specific storage-class specifier).
Quoting C11, chapter §6.2.2, Linkages of identifiers
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.
Related
Is it fine to write a forward declaration of a function with a static keyword but implemet it later in the file without the static keyword?
For example:
#include <stdio.h> /* printf */
static void func();
int main()
{
func();
return(0);
}
void func()
{
printf("Hello World");
}
It compiles and runs without any errors, but would func be a static function or not and why?
C 2018 6.2.2 5 says a function declaration without a storage-class specifier (such as extern or static) is the same as using extern:
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…
C 2018 6.2.2 4 says a declaration with extern after a declaration with static that is visible1 uses the internal linkage established by the static:
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.
So the behavior is defined to use internal linkage, and I am fairly confident there is nothing in the C standard that overrides this.
Footnote
1 An earlier declaration of a function declared at file scope could be hidden by a declaration of the same identifier in block scope. Then the earlier declaration would not be visible in that block.
This question already has answers here:
About Tentative definition
(2 answers)
In C,why is multiple declarations working fine for a global variable but not for a local variable?
(3 answers)
Closed 5 years ago.
/*How does this code compiles and executes in C?*/
#include <stdio.h>
int x= 9; //Varaible initialization
int x; //Variable declaration, same name
int main(void) {
printf("%d", x); //output: 9
return 0;
}
There should be an error while compilation as same variable is used. How come the code compiles?
From standard 6.9.2p2 you can know about this - this is known as tentative definition.
From here
A tentative definition is an external declaration without an initializer, and either without a storage-class specifier or with the specifier static.
A tentative definition is a declaration that may or may not act as a definition. If an actual external definition is found earlier or later in the same translation unit, then the tentative definition just acts as a declaration.
int i1 = 1; // definition, external linkage
int i1; // tentative definition, acts as declaration because i1 is defined.
So from these two references it is clear that the second one merely boils down a declaration or valid tentattive definition on standard words and the value it takes is the one assigned that is 1.
Sane goes here for you with the value of x being 9.
You can declare a global variable or function as many times as you wish. But you must have only one definition. The first line assigns the variable a value, so it is a declaration and definition combined. The second line does not assign a value, so it is only a declaration.
In Global scope two variable with same name is possible but one should be un-intialized(weak symbol) and another one should be initialized(strong symbol).
int x= 9; /* strong symbol i.e declaration with definition*/
int x; /* weak symbol i.e only declaration */
while choosing among two, priority is given two strong symbol.
Note : compiler won't allow to have two strong symbol at a time, that would be a re-definition of variable.
The second one is not a definition. It's a declaration.
From the ISO C standard draft N1570, Section 6.9.2:
1 If the declaration of an identifier for an object has file scope and an initializer, the declaration is an external definition for the identifier.
2 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 when you write
int x;
in file scope, it's not necessarily a definition. It's a declaration, which is fine to be repeated.
This is called tentative definition in C. See more here, here and here.
This question already has answers here:
Using extern keyword to call functions
(4 answers)
Effects of the extern keyword on C functions
(10 answers)
Should functions be made "extern" in header files?
(5 answers)
Is extern keyword for function necessary at all in C?
(4 answers)
Closed 5 years ago.
Is there any difference between declaring a function (bar) this way:
char *foo(char *pch)
{
extern char *bar(); /* this line here */
...
}
Or this way?
char *foo(char *pch)
{
char *bar(); /* this line here */
...
}
The 2011 C Standard says in 6.2.2/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.
So there is no technical difference.
But as already noted in the comments, both are considered bad style. A function declaration does not belong inside another function where it will be used. If you use that pattern and want to change the declaration of the function, you would need to find and modify all the places it's used! A function with external linkage should be declared in a header file. A function with internal linkage (using the static keyword) should be declared somewhere near the beginning of a source file.
This question already has answers here:
Tentative definitions in C and linking
(3 answers)
Closed 6 years ago.
#include<stdio.h>
int check,check;
void main(){
printf("Hello!!");
}
When I compile this piece of code, everything goes on normal but when I give this inside the main function,
#include<stdio.h>
void main(){
int check,check;
printf("Hello!!");
}
I get an error like
C:\MinGW\bin>cc ex1.c
ex1.c: In function 'main':
ex1.c:4:11: error: redeclaration of 'check' with no linkage
int check,check;
^
ex1.c:4:5: note: previous declaration of 'check' was here
int check,check;
^
Why is it so?
This is possible in global scope, because that is considered an tentative definition.
Quoting C11, chapter §6.9.2
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.
However, in the block scope (function scope), there's no tentative definition, hence the code tries to create two identifiers with the same name which is cause for the re-declaration error, because they actually denote the same object.
You can read more about it here.
That said, since C99, for hosted enviroments, void main() is not a valid signature anymore, it has to be int main(void) at least.
I am aware about C linking rules presented in the following excerpts from C standard:
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. 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.
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.
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.
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.
7/ If, within a translation unit, the same identifier appears with
both internal and external linkage, the behavior is undefined.
I understand that extern keyword is optional before functions declarations because they are external by default but there are some functions prototypes preceded by extern in stdlib.h such as:
extern void qsort (void *__base, size_t __nmemb, size_t __size,
__compar_fn_t __compar) __nonnull ((1, 4));
Also, why gcc handles situations described in point 7 differently when it comes to functions and variables. In this example both function foo and variable d are defined both in internal and external scope but only variable definition raises error:
static int foo(void);
int foo(void); /* legal */
static double d;
double d; /* illegal */
One can freely place or not place extern before function declaration, so it should not be surprising that one can found it somewhere. Regarding second question:
C11 draft (n1570.pdf) has example in page 159 related to tentative definitions:
static int i5; // tentative definition, internal linkage
// ...
int i5; // 6.2.2 renders undefined, linkage disagreement
extern int i5; // refers to previous, internal linkage
6.2.2 is what you have posted. So, it does not work in this case because there are two tentative definitions with different linkages, so there is p.7 violation. On the other hand, it works with external specifier (as foo functions from your example), because p.4 is enforce - later declaration refers to linkage defined in first declaration. In other words, case with variables does not work because they are objects and tentative definition rules are involved. At least standard contains explicit example which clearly explains what comittee wanted to say.