I know that static keyword makes a C function/variable is file-scoped.
And I've read that If I want to make a variable global scope (accessed by more than one file), I should do:
in the .c file:
int my_global_var;
// main()....
in the .h file:
extern int my_global_var;
So, any one will include my .h file will be able to reference my_global_var which is already externed.
And I read also this is required for functions as well but I am using gcc 4.x and I don't extern the function in the .h file and other programs can successfully link it.
So, the question is...
Is the behavior of the non-static function linkage is the default or should I extern non-static functions to adhere to the standard??
From the standard, 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. If
the declaration of an identifier for
an object has file scope and no
storage-class specifier, its linkage
is external.
Meaning, it's extern by default.
Both function and object declarations are extern by default. However, you need to add an explicit extern to your object declarations in header files to avoid a re-definition: without a storage-class specifier, any file-scoped object declaration will actually be something called a tentative definition and reserve storage for the object within the current translation-unit.
For consistency, I unnecessarily use extern even for function declarations. In most cases, I declare objects within headers as one of
extern int foo;
static const int bar = 42;
and functions as one of
extern int spam(void);
static inline int eggs(void) { return 42; }
Related
I've been diving deeper into the C standard, and I'm confused about the way it talks about linkage and tentative definitions.
First, in this part of the standard it is stated that
extern (keyword) means static duration and external linkage (unless already declared internal)
static storage duration. The storage duration is the entire execution of the program, and the value
stored in the object is initialized only once, prior to main function. All objects declared static and
all objects with either internal or external linkage that aren't declared _Thread_local (since C11)
have this storage duration.
external linkage. The identifier can be referred to from any other translation units in the entire
program. All non-static functions, all extern variables (unless earlier declared static), and all file-
scope non-static variables have this linkage.
so far we have that variables declared in file scope have static storage duration and external linkage by default. Also, objects with static storage duration are initialized to zero, before the program starts.
But, after reading this part (tentative definitions) and this part (declarations) I can't find where it says that objects with an explicit "extern" keyword are not allocated storage.
Please be careful about the difference between the "extern" keyword itself and the term "external declarations".
"External declarations" are defined as
At the top level of a translation unit (that is, a source file with all the #includes after the preprocessor), every C program is a sequence of declarations, which declare functions and objects with external linkage. These declarations are known as external declarations because they appear outside of any function.
regardless of the presence or absence of an explicit "extern" keyword.
I suppose that my concrete question is where in the standard does it say that file scope objects, that have an implicit external linkage by default, are not allocated storage if they are declared with an explicit "extern".
I know this is the case because if one declares the same identifier in multiple translation units all but one must have "extern" so as not to get a redefinition error.
First, while cppreference.com has useful information it is not the C standard. The C11 standard can be found here.
This comes down to the difference between a declaration and a definition.
For an object, a declaration basically states that an object with a given type exists somewhere, while a definition is what actually allocates space for the object.
These terms are specified in sectin 6.7p5 of the C standard:
A declaration specifies the interpretation and attributes of a set of
identifiers. A definition of an identifier is a declaration for
that identifier that:
for an object, causes storage to be reserved for that object;
for a function, includes the function body;
for an enumeration constant, is the (only) declaration of the identifier;
for a typedef name, is the first (or only) declaration of the identifier.
By applying the extern keyword, if there is no initializer then this constitutes a declaration, and a declaration does not allocate storage for an object. Section 6.9.2p1-2 spells this out:
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.
A declaration with extern and no initializer does not fit the above definition of a tentative definition or an external definition.
Section 6.9.2p4 gives examples of declarations and definitions:
int i1 = 1; //definition, external linkage
static int i2 = 2; //definition, internal linkage
extern int i3 = 3; //definition, external linkage
int i4; //tentative definition, external linkage
static int i5; //tentative definition, internal linkage
int i1; //valid tentative definition, refers to previous
int i2; //6.2.2 renders undefined, linkage disagreement
int i3; //valid tentative definition, refers to previous
int i4; //valid tentative definition, refers to previous
int i5; //6.2.2 renders undefined, linkage disagreement
extern int i1; //refers to previous, whose linkage is external
extern int i2; //refers to previous, whose linkage is internal
extern int i3; //refers to previous, whose linkage is external
extern int i4; //refers to previous, whose linkage is external
extern int i5; //refers to previous, whose linkage is internal
In the C Standard (6.9.2 External object definitions ) there is written that
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.
So if you will write at file scope
extern int x = 1;
then this declaration with the storage-class specifier extern will be at the same time a definition of the object x.
Otherwise if an object is declared at file scope without an initializer but with the storage-class specifier extern then the compiler assumes that the object is defined in some other translation unit or in the same translation unit but somewhere else.
For example (here is declared a variable at file scope with internal linkage)
#include <stdio.h>
static int x = 10;
extern int x;
int main(void)
{
printf( "x = %d\n", x );
return 0;
}
If an object is declared at file scope without the storage-class specifier extern then the compiler generates a tentative definition.
I have heard that functions in are called "extern" by default. So, according to this the scope of functions should be inside, entire the project, isn't it? I believe haven't seen this. I just like to know that is it really visible across the project files by default?
The article link: https://www.geeksforgeeks.org/understanding-extern-keyword-in-c/
It says:
" First, Let’s consider the use of extern in functions. It turns out that when a function is declared or defined, the extern keyword is implicitly assumed. When we write.
int foo(int arg1, char arg2);
The compiler treats it as: extern int foo(int arg1, char arg2);
Since the extern keyword extends the function’s visibility to the whole program, the function can be used (called) anywhere in any of the files of the whole program, provided those files contain a declaration of the function. (With the declaration of the function in place, the compiler knows the definition of the function exists somewhere else and it goes ahead and compiles the file). So that’s all about extern and functions. "
You can find this in section "6.2.2 Linkages of identifiers" of the C11 standard draft N1570.
It says:
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.
The use of the extern modifier is optional for function definitions. However, many C developers use it as a matter of style, to indicate to somebody reading the source that there's no point looking for the definition of the function in the same file.
Yes all functions (if there is no other modifier) are implicitly extern. You may alter it with static modifier, which makes the function visible only for the file it is written in. Another quite common use is extern inline which makes inline functions visible for another files, not just the module they are defined in.
Yes, C defaults to global visibility for new named objects in filescope unless they're declared static.
Note that extern does not mean global visibility. It means previously declared visiblity OR (if there was no such previous declaration) global visibility.
extern optional on non-static functions (with some special meanings for the new (C>=C11) inline functions) but for filescope variable declarations it is sometimes needed to differentiate between a declaration and a tentative definition.
Examples:
void globalFunc(void);
void globalFunc(void){ }
static void fileLocalFunc(void);
void fileLocalFunc(void){ } //ok, file-local because the previous declaration was file-local
static void another_fileLocalFunc(void);
extern void another_fileLocalFunc(void){ } //extern is optional for functions
static int fileLocal_variable;
extern int fileLocal_variable; //ok, file-local, because the previous declaration was file-local
//some noncompiling stuff:
#if 0 || CONFLICTING_FUNC_DECLARATIONS0
extern void conflictingFuncDeclarations0(void);
static void conflictingFuncDeclarations0(void);
#endif
#if 0 || CONFLICTING_FUNC_DECLARATIONS1
void conflictingFuncDeclarations1(void);
static void conflictingFuncDeclarations1(void);
#endif
#if 0 || CONFLICTING_VAR_DECLARATIONS0
int conflictingVarDeclarations0;
static int conflictingVarDeclarations0;
#endif
If you're on a POSIX system, you can compile a translation unit into an object (*.o) file and then use the nm utility on it to see which names it exports (or attempts to import).
I'm reading the source of a C project and am trying to discern why a particular use of extern is being used. (Note: This question is related but for C++, not C.) Say I have four header files that each declare an extern const struct:
extern const struct puppy fido;
This struct is defined in a source file like so:
extern const struct puppy fido;
static const struct puppy *puppies[] = { &fido };
const struct puppy fido = { "fido", 10, 10 };
Is there some kind of benefit to marking the variable declaration as extern in the source file, when those variables are defined in that very same source file?
The only advantage would be that any code between the declaration and the definition will be able to access the variable. Apart from that, the extern declaration in the same file is pointless.
Lundin is correct, that in this case extern does not affect visibility of fido in other source files. In your example code, it is used as a forward declaration.
Relevant part from C99 standard, section 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.
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 C++, behavior would be different, because variables declared with const are implicitly static. In C++, you are required to declare the variable with extern the first time, or other compilation units would not find it.
C++98 standard, section 3.5.3:
A name having namespace scope (3.3.5) has internal linkage if it is the name of
— an object, reference, function or function template that is explicitly declared static or,
— an object or reference that is explicitly declared const and neither explicitly declared extern nor previously declared to have external linkage;
Sometimes, when you write a source file, you just want a piece of a header file, not the whole thing.
Repeating the extern declaration in the source file allows you not to include the header file in that specific source file.
This is not necessarily a good practice.
extern const struct puppy fido;
// ...
const struct puppy fido = { "fido", 10, 10 };
If const struct puppy fido = { "fido", 10, 10 }; is compiled in 2 different .c files, it will fail. There should be #ifndef and endif before and after the const struct puppy fido = { "fido", 10, 10 }; in order to include it once.
A good practice (globals variables have to be avoided in general) is to declare with extern in the .h files, and to put the definition of the variable in a .c file.
a)The definition of an external variable is same as that of a local variable,ie, int i=2; (only outside all functions).
But why is extern int i=2; too working as the definition? Isn't extern used only in variable declaration in other files?
b)file 1
#include<stdio.h>
int i=3;
int main()
{
printf("%d",i);
fn();
}
file2
int i; // although the declaration should be: extern int i; So, why is this working?
void fn()
{
printf("%d",i);
}
OUTPUT: 3 in both cases
For historical reasons, the rules for determination of linkage and when a declaration provides a definition are a bit of a mess.
For your particular example, at file scope
extern int i = 2;
and
int i = 2;
are equivalent external definitions, ie extern is optional if you provide an initializer.
However, if you do not provide an initializer, extern is not optional:
int i;
is a tentative definition with external linkage, which becomes an external definition equivalent to
int i = 0;
if the translation unit doesn't contain another definition with explicit initializer.
This is different from
extern int i;
which is never a definition. If there already is another declaration of the same identifier visible, then the variable will get its linkage from that; if this is the first declaration, the variable will have external linkage.
This means that in your second example, both file1 and file2 provide an external definition of i, which is undefined behaviour, and the linker is free to choose the definition it likes best (it may also try to make demons fly out of your nose). There's a common extension to C (see C99 Annex J.5.11 and this question) which makes this particular case well-defined.
In C, an extern with an initialization results in a variable being allocated. That is the declaration will be considered a defining declaration. This is in contrast with the more common use of extern.
The C standard says:
6.9.2 External object definitions
.....
If the declaration of an identifier for an object has file scope and an initializer, the
declaration is an external definition for the identifier.
As for the second part of your question, your declaration int i at file scope has external linkage. If you want to give it internal linkage you need to declare it static int i. The C standard says:
6.2.2 Linkages of identifiers
......
If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external.
#include <stdio.h>
static i = 5;
int main()
{
extern int i;
printf("%d\n",i);
return 0;
}
Can someone give any use-case for declaring a static variable as extern inside a function block?
NEW:
Why is this not allowed?
int main()
{
static i = 5;
extern int i;
printf("%d\n",i);
return 0;
}
this is useful when you need to access a variable that resides within another translation unit, without exposing the external variable globally (for a few reasons, like name collision, or that the the variable shouldn't be directly accessed, so static was used to limit its scope, but that TU's header still needs access).
As an example, lets say we have a translation unit foo.c, it contains:
//foo.c
static int i = 0;
i shouldn't be changed or directly accessed outside foo.c, however, foo.h comes along requiring access to i for an inline function, but i shouldn't be exposed to any translation unit using foo.h, so we can use extern at functional level, to expose it only during the scope of IncI, the inline function requiring the use of i:
//foo.h
inline void IncI(int val)
{
extern int i;
i += val;
}
Your second example is 'disallowed' because the compiler thinks you are trying to bind two different variables to the same symbol name, ie: it creates the static i at local scope, but searches for the extern int i at global scope, but doesn't find it, because static i as at the function scope. a more clever compiler would just fix the linkage to the static i, whether or not this follows standards I wouldn't know.
Now that I have a C standards document to work from (shame on me I know...), we can see what the official stance is (in C99):
6.2.2 Linkages of identifiers
Section 3:
If the declaration of a file scope identifier for an object or a function contains the storageclass
specifier static, the identifier has internal linkage.
Section 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.
thus, because static will cause internal linkage, the extern will bring that linkage into the current scope. there is also a footnote stating that this may cause hiding of variables:
23) As specified in 6.2.1, the later declaration might hide the prior declaration.
In your second case, you are telling the compiler you have a static (local) variable i and another (global) variable i that is defined somewhere else.