Does this invoke undefined behavior with linkage in C? - c

From section (6.2.2/7) C99 Standard
7. If, within a translation unit, the same identifier appears with
both internal and external linkage, the behavior is undefined.
While the following generates a compile time error due to conflict of definitions
// 'x' has external linkage
extern int x;
// Here, 'x' has internal linkage
static int x;
But the following compiles fine,
// 'x' has external linkage
extern int x;
void foo() {
// Here, 'x' has internal linkage
static int x;
}
Do both the cases invoke an undefined behavior?

Your question stems from an incorrect assumption that a locally declared static variable has internal linkage. In reality a static variable declared in a block scope has no linkage. See 6.2.2/6
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.
Only file-scope declaration can have external or internal linkage (plus local extern declarations).
Therefore 6.2.2/7 and your question simply do not apply.

As far as I know, it doesn't, since the two variables aren't the same. The local variable takes priority over the global one, and in the scope of foo(), it's declared only once. See the assembler output - the compiler will most likely translate the two variables into two different symbols.

Related

Simultaneously creating internal and external linkages in C

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.

Can a variable be both static and extern [duplicate]

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.

Shall an variable with external linkage be defined with keyword external?

From https://www.quora.com/What-are-the-types-of-linkages-in-C-programming
External linkage, means that the variable could be defined somewhere
else outside the file you are working on, which means you can define
it inside any other translation unit rather your current one (you
will have to use the keyword extern when defining it in the other
source code).
Internal linkage, means that the variable must be defined in your
translation unit scope, which means it should either be defined in any
of the included libraries, or in the same file scope.
None linkage, points to the default functions and braces scopes, such
as defining an auto variable inside a function, this will make the
variable only accessable within that function's scope.
Note that:
Any global object is externally linked by default, you can disable that by using the keyword static.
Any constant global object is internally linked by default, you can
disable that by using the keyword extern.
Suppose a global variable is defined in file1 and I want to use it in file2.
In file1, shall the global variable be defined with keyword
extern?
The quote above seem to contradict itself:
"you will have to use the keyword extern when defining it in the other source code" seems to say it should.
"Any global object is externally linked by default" seems to say that it doesn't need to.
In file2, shall I declare global variable with keyword extern?
tldr: You should declare the variable, with extern, in a header file which is included by both file1 and file2. You should then define the variable in file1 only. To define the variable, you declare it without extern (and also without static).
You sound like you have gotten the extern keyword and the standardese term "external linkage" mixed up.
A variable with "external linkage" is accessible from any function in the program, as long as a declaration of the variable is visible to that function. In contrast, a variable with "internal linkage" is accessible from, at most, one "translation unit" (a single source file and all the files it includes), and a variable with "no linkage" is only visible within a single function. (I don't remember off the top of my head whether a static variable declared within a function is considered to have internal linkage or no linkage.)
The extern keyword, applied to a variable declaration, has two effects. First, it guarantees that that variable will be given external linkage, even if the declaration is inside a function (don't do that). Second, and much more importantly, it makes the declaration not be a definition. What that means is, if you have these two files
/* file1.c */
extern int foo;
/* file2.c */
extern int foo;
int main(void) { return foo; }
their combination is not a valid program. You will get an error from the linker, probably reading something like "undefined reference to foo".
To make this a valid program, you must remove the extern from one of the two declarations of foo. That declaration then becomes a definition, and the program will link. (Also, that declaration can then be given an initializer, if you want it to have a value other than 0 at startup.)
If you remove the extern from both of the definitions of foo, the result is, IIRC, implementation-defined. Some C compilers will merge them into a single global variable, and others will issue a link-time error. Sometimes the behavior depends on whether or not the variables have initializers.
It is OK to write
/* file1.c */
extern int foo;
/* file2.c */
extern int foo;
int foo;
This allows you to put the extern declaration in a header file that both .c files include, which reduces the risk of the declarations coming to have inconsistent types (if this happens, the program will exhibit undefined behavior).
c11 draft, 6.2.2, 4th section, states:
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.
i don't think there will be any difference with or without extern keyword. some experiment also indicates that:
following 2 compiled:
extern int a;
extern int a;
int a = 20;
and
extern int a;
int a;
int a = 20;
but not this one:
extern int a;
int a = 10;
int a = 20;
however, i have some impression that once i read about the different behavior when dynamic linkage get involved in windows. I cannot find it though. it would be nice if anyone can confirm.
The text you quoted has a lot of errors. I would recommend not relying on information from that site.
(you will have to use the keyword extern when defining it in the other source code).
Not true, as file-scope definitions have external linkage unless the static keyword is used (or no specifier is used and they are re-declaring something already declared with the static keyword).
It is possible to include a redundant extern in the definition, however there must also be an initializer (otherwise it would be a declaration and not a definition).
Internal linkage, means that the variable must be defined in your translation unit scope, which means it should either be defined in any of the included libraries, or in the same file scope.
Presumably this means "included headers", not "included libraries".
Any constant global object is internally linked by default, you can disable that by using the keyword extern.
This is wrong, "global objects" have external linkage unless declared with static. The author might be mixing up C with C++ (in the latter, const global objects have internal linkage unless otherwise specified).
Suppose a global variable is defined in file1 and I want to use it in file2.
// file1.h (or any other header)
extern object_t obj;
// file1.c
#include "file1.h"
object_t obj; // or: extern object_t obj = { 1, 2, 3 };
// file2.c
#include "file1.h"

Why do we need the 'extern' keyword in C if file scope declarations have external linkage by default?

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.

What is the difference between static int a and int a? [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Difference between 'global' and 'static global'
What is the difference between statements 1 and 2 :-
#include <stdio.h>
//In the global declaration area
static int a; // 1.
int b; // 2.
Thanks for help.
A static global variable is local to the translation unit it is defined in. So, if you define static int a; in two different translation units, this will create two independent variables. If you define a non-static global variable int b; in two translation units, you will experience a linker error (but you can use extern int b; in one of the two translation units to tell the linker that it should use the global variable from the other translation unit).
Both are variable definitions, however, the static keyword applied to a variable in the "global declaration area" restricts that global variable to be seen only in the translation unit in which it is defined.
They are both in memory for the entire lifetime of the program. The variable that is declared static only has scope in the file in which it is declared where as the variable declared without static can be accessed from other files using an extern declaration.
Original source - http://bytes.com/topic/c/answers/860211-global-variable-static-global-variable
static int a is only accessible within that file. int b can be accessed with extern int b from a different file.
static int a;
int b;
a has internal linkage. b has extern linkage.
C99 6.2.2
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.
A static variable's life extends across the lifetime of the program. However, scope rules still apply.
If you define your static variable outside of a method (normally at the beginning of the class) your variable will be available from anywhere within that class.
You can't change the value of these objects. They're normally used for storing things like API keys.

Resources