Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tentative definitions in C and linking

Consider the C program composed of two files,

f1.c:

int x;

f2.c:

int x=2;

My reading of paragraph 6.9.2 of the C99 standard is that this program should be rejected. In my interpretation of 6.9.2, variable x is tentatively defined in f1.c, but this tentative definition becomes an actual definition at the end of the translation unit, and (in my opinion), should therefore behave as if f1.c contained the definition int x=0;.

With all compilers (and, importantly, linkers) I was able to try, this is not what happens. All compilation platforms I tried do link the above two files, and the value of x is 2 in both files.

I doubt this happens by accident, or just as an "easy" feature to provide in addition to what the standard requires. If you think about it, it means there is special support in the linker for those global variables that do not have an initializer, as opposed to those explicitly initialized to zero. Someone told me that the linker feature may be necessary to compile Fortran anyway. That would be a reasonable explanation.

Any thoughts about this? Other interpretations of the standard? Names of platforms on which files f1.c and f2.c refuse to be linked together?

Note: this is important because the question occurs in the context of static analysis. If the two files may refuse to be linked on some platform, the analyzer should complain, but if every compilation platform accepts it then there is no reason to warn about it.

like image 235
Pascal Cuoq Avatar asked Sep 29 '09 05:09

Pascal Cuoq


People also ask

What is tentative in C?

Beginning of C only. A tentative definition is any external data declaration that has no storage class specifier and no initializer. A tentative definition becomes a full definition if the end of the translation unit is reached and no definition has appeared with an initializer for the identifier.

What is meant by linkages in C?

In C, all identifiers are lexically (or statically) scoped. Linkage : Linkage describes how names can or can not refer to the same entity throughout the whole program or one single translation unit. The above sounds similar to Scope, but it is not so.

What is tentative variable?

Assigns tentative values for the variables in a term. These are typically used to register values the variables are given in a partial or initially inconsistent solution. These values may be changed through later calls to the same predicate.

What is a tentative definition in C?

Tentative definitions Beginning of C only. A tentative definitionis any external data declaration that has no storage class specifier and no initializer. A tentative definition becomes a full definition if the end of the translation unit is reached and no definition has appeared with an initializer for the identifier.

What constitutes a tentative definition of an external object?

Then, according to latest C99 draft 6.9.2 External object definitions p. 2 (emphasis mine): 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.

What is the difference between an external declaration and tentative definition?

The identifiers introduced by external declarations have file scope . 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.

Should I comment out tentative definitions in header files?

If you comment out the definition in example.c, the tentative definition acts as a definition with an initializer of 0: But it can be considered to be better style to restrict header files to contain declarations, and not definitions, not even tentative ones.


2 Answers

See also What are extern variables in C. This is mentioned in the C standard in informative Annex J as a common extension:

J.5.11 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).

Warning

As @litb points out here, and as stated in my answer to the cross-referenced question, using multiple definitions for a global variable leads to undefined behaviour, which is the standard's way of saying "anything could happen". One of the things that can happen is that the program behaves as you expect; and J.5.11 says, approximately, "you might be lucky more often than you deserve". But a program that relies on multiple definitions of an extern variable - with or without the explicit 'extern' keyword - is not a strictly conforming program and not guaranteed to work everywhere. Equivalently: it contains a bug which may or may not show itself.

like image 106
Jonathan Leffler Avatar answered Oct 02 '22 21:10

Jonathan Leffler


There is something called a "common extension" to the standard, where defining variables multiple times is allowed as long as the variable is initialized only once. See http://c-faq.com/decl/decldef.html

The linked page says this is pertinent to Unix platforms--I guess it's the same for c99 as c89--though maybe it has been adopted by more compilers to form some sort of a defacto standard. Interesting.

like image 42
olovb Avatar answered Oct 02 '22 21:10

olovb