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.)
Related
Section 6.11.2 of the C standard states one of the features that may be deprecated in future versions:
Declaring an identifier with internal linkage at file scope without
the static storage-class specifier is an obsolescent feature.
How is it even possible to declare a file scope identifier to have internal linkage without the static storage-class specifier?
There is a specific example for this issue in the C++ standard.
In [dcl.stc]:
static int b; // b has internal linkage
extern int b; // b still has internal linkage
So in the second line, b is declared as a file scope identifier with internal linkage without the keyword static.
The example is also true for C, as C11:6.2.2 says:
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.
see this question for more detail
This is a 'language-lawyer' type question about a corner case in the C11 Standard.
The rules that determine the linkage of an identifier in a C program are spelled out in
clause 6.2.2 of the C11 Standard. In particular, 6.2.2(5) states that (emphasis mine):
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 case of a declaration such as _Thread_local int a; in a file scope, 6.2.2(5) above does not apply,
since _Thread_local is a storage specifier. None of the other provisions of 6.2.2 apply, either
(no static so (3) does not apply, not in block scope, is an object and not a parameter, so (6) is not applicable, etc.). So what
should the linkage of a be according to the Standard? Am I missing some other rules that determine the linkage in this case?
I understand that the intention is to make it have external linkage (which is how gcc treats this case) but how
does this follow from the Standard itself?
Note that is is perfectly ok to have a declaration like
static _Thread_local int a; extern _Thread_local int a; in which case 6.2.2 rules apply just fine making a have internal linkage (that extern notwithstanding).
Finally, the semantics of _Thread_local are not relevant here.
As I read it, per C11 6.2.4p4, at file scope _Thread_local applies to the thread of main(), effectively moving them as static or extern references in the { } block of main(), rather than auto, and left implementation-defined how thread functions other than main() have access to them. I agree it appears to be a defect that it does not mention that the defining declaration of any object that is _Thread_local should be required to have static or extern as additional qualifier, not just 'may appear' as a referencing declaration, in 6.7.1p2.
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???
I am intermediate level C programmer. I was walking through a simple code snippet in C
int a ; // A
const int b; // B
static int c; //C
void func(int d) // D
{
//.....
}
What are the linkage of variables a,b,c and d. I am quite sure that a by default has external linkage, b, c and d have internal linkage. Is my understanding correct?
This is my first question at this site.
From section 6.2.2, Linkages of identifiers, of C99, the definitive source:
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.
Now, tackling your variables one by one:
a is covered by part 5 since it's "an identifier for an object [that] has file scope and no storage-class specifier". It therefore has external linkage.
b is also covered by part 5 (file scope, no storage-class specifier). Hence external linkage.
c is covered by part 3 since it has the static storage-class specifier - it has internal linkage.
finally, d is covered by part 6, being a function parameter - it has no linkage.
In C, a and b have external linkage and c has internal linkage. In C++ you'd be right,that b would also have internal linkage.
For case "D", I'm not sure which you're talking about: the function or the parameter. func has external linkage; d has no linkage.
I am quite sure that a by default has external linkage, b, c and d have internal linkage. Is my understanding correct?
No! d has no-linkage because it is a formal parameter.
From C99
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.
Furthermore b has external linkage in C99. In C++ const-qualified variables at file scope have internal linkage.
a,b and c all have identical linkage, if they are declared in global scope which it looks like they are
d is a function parameter, and is created when that function is called and no longer exists when the function returns
Why can't I have int a; in 2 C files. I intend to combine both to make executable.
I know from experience that I can't, but I want to find where the standard C99 says this and seal my understanding.
I am reading ISO C99 standard from http://www.open-std.org/jtc1/sc22/wg...docs/n1256.pdf. It says on page 42:
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.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.
After reading this it looks that if I declare a variable like say int a; in 2 source files. then both have external linkage as per rule 5 and 4. and then as per rule 2, both should refer to the same object. Then why does the compiler create problem. Where in the standard it is hinted that we can't declare like this in 2 source files and this should throw compilation error. Firstly, where in the standard, it says that int a is a definition, and then where it says that 2 instances of definitions are not acceptable. I know that it is not allowed from my experience, but it would be very useful to me, if I can find this in the standard and seal my understanding.
Do the following excerpts from the standard in combination amount to this rule? or I have missed that glue? :
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 or typedef name, is the
(only) declaration of the identifier.
As discussed in 5.1.1.1, the unit of
program text after preprocessing is a
translation unit, which consists of a
sequence of external declarations.
These are described as ‘‘external’’
because theyappear outside anyfunction
(and hence have file scope). As
discussed in 6.7, a declaration that
also causes storage to be reserved for
an object or a function named by the
identifier is a 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.
Thanks.
I think you need 6.9.2/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.
and 6.9/5:
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.
Basically, int a; is a tentative definition. You can have multiple tentative definitions in a single translation unit but the effect is the same as having one non-tentative external definition (e.g. something like int a = 0;). Having more that one definition of an object with external linkage in a program is a violation of 6.9/5.
Note that it is a "common extension" to allow more than one external definitions of an object so long as at most only one is initialized and the definitions agree (see J.5.11).