What is the rationale behind tentative definitions in C? - c

Consider following program. Will this give any compilation errors?
#include <stdio.h>
int s=5;
int s;
int main(void)
{
printf("%d",s);
}
At first glance it seems that compiler will give variable redefinition error but program is perfectly valid according to C standard. (See live demo here http://ideone.com/Xyo5SY).
A tentative definition is any external data declaration that has no storage class specifier and no initializer.
C99 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.
My question is, what is rationale for allowing tentative definitions? Is there any use of this in C? Why does C allow tentative definitions?

Tentative definitions was created as a way to bridge incompatible models that existed pre-C89. This is covered in the C99 rationale section 6.9.2 External object definitions which says:
Prior to C90, implementations varied widely with regard to forward
referencing identifiers with internal linkage (see §6.2.2). The C89
committee invented the concept of tentative definition to handle this
situation. A tentative definition is a declaration that may or may not
act as a definition: If an actual definition is found later in the
translation unit, then the tentative definition just acts as a
declaration. If not, then the tentative definition acts as an actual
definition. For the sake of consistency, the same rules apply to
identifiers with external linkage, although they're not strictly
necessary.
and section 6.2.2 from the C99 rationale says:
The definition model to be used for objects with external linkage was
a major C89 standardization issue. The basic problem was to decide
which declarations of an object define storage for the object, and
which merely reference an existing object. A related problem was
whether multiple definitions of storage are allowed, or only one is
acceptable. Pre-C89 implementations exhibit at least four different
models, listed here in order of increasing restrictiveness:

Here's an example of a case where it's useful:
void (*a)();
void bar();
void foo()
{
a = bar;
}
static void (*a)() = foo;
/* ... code that uses a ... */
The key point is that the definition of foo has to refer to a, and the definition of a has to refer to foo. Similar examples with initialized structures should also be possible.

Related

Variable declaration and definition mismatch

I am using a C89 compiler (embedded systems).
I ran into some C code where one translation unit defines a variable as bool varName;, where bool is a typedef of unsigned char. Another translation unit forward declares the variable as follows: extern char varName;.
This is obviously a type mismatch, and is an error. My question is, what exact rule does this violate? My knee-jerk reaction was that it is an ODR violation, but there is a single definition so I'm not confident that this is an ODR violation.
6.2.7p2
All declarations that refer to the same object or function shall have
compatible type; otherwise, the behavior is undefined.
The C89 standard has the same paragraph.
Declarations referfing to the same object is further explained in the paragraph on linkage:
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.
In the set of translation units and libraries that constitutes an
entire program, each instance of a particular identifier with external
linkage denotes the same object or function. Within one translation
unit, each instance of an identifier with internal linkage denotes the
same object or function. Identifiers with no linkage denote unique
entities.
Compatible types essentially means identical types, with some minor caveats (e.g., extern int foo[]; is compatible with extern int foo[3];).

What is the formal way to determine the linkage of a `_Thread_local` identifier?

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.

Is extern keyword in C redundant?

I have found that I could achieve the desired results without using extern (though I do agree that it gives reader some kind of an hint about the variable). In some cases using extern gave undesired results.
xyz.h
int i;
file1.c
#include "xyz.h"
....
i=10;
....
file2.c
#include "xyz.h"
main()
{
printf("i=%d\n",i);
}
Of course, it was a large project, broke it down for simple understanding. With extern keyword, I couldnt get desired results. In fact, I got linker error for the variable i with "extern" approach.
Code with "extern" approach,
file1.c
int i;
main()
{
i=10;
}
file2.c
extern int i;
foo()
{
printf("i=%d\n",i);
}
This gave linker error. I just wanted to know why it worked in the first case and also the practical case where we cannot do it without using the keyword "extern". Thanks.
Formally, your first program is invalid. Defining a variable in header file and then including this header file into multiple translation units will ultimately result in multiple definitions of the same entity with external linkage. This is a constraint violation in C.
6.9 External definitions
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.
The definition of i in your first example is a tentative definition (as it has been mentioned in the comments), but it turns into a regular full fledged external definition of i at the end of each translation unit that includes the header file. So, the "tentativeness" of that definition does not change anything from the "whole program" point of view. It is not really germane to the matter at hand (aside for a little remark below).
What makes your first example to compile without error is a popular compiler extension, which is even mentioned as such in the language standard.
J.5 Common extensions
J.5.11 Multiple external definitions
1 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).
(It is quite possible that what originally led to that compiler extension in C is some implementational peculiarities of tentative definition support, but at abstract language level tentative definitions have nothing to do with this.)
Your second program is valid with regard to i (BTW, implicit int is no longer supported in C). I don't see how you could get any linker errors from it.
There are at least 2 cases where extern is meaningful and not "redundant":
For objects (not functions) at file scope, it declares the object with external linkage without providing a tentative definition; tentative definitions turn into full definitions at the end of a translation unit, and having the same identifier defined with external linkage in multiple translation units is not permitted.
At block scope (in a function), extern allows you to declare and access an object or function with external linkage without bringing the identifier into file scope (so it's not visible outside the block with the declaration). This is useful if the name could conflict with something else at file scope. For example:
static int a;
int foo(void)
{
return a;
}
int bar(void)
{
extern int a;
return a;
}
Without the extern keyword in bar, int a; would yield a local variable (automatic storage).

Declaration and definition in C programming with extern

This may seem simple to one's eye but, this question is itching me in many ways.
my question is about declaration and defenition on variables in c.
there are actually many explanation in internet regarding this one and there is not just one solution to this issue as many view points are placed in this issue. i want to know the clear existance of this issue.
int a;
just take this is this a declaration or definition?, this one when i use printf, it has 0 as value and address as 2335860. but if this declaration then how come memory is allocated for this.
int a;
int a;
when i do this it says previous declaration of 'a' was here and redeclaration of 'a' with no linkage.
some sources say redeclaration is permitted in c and some say dont what is the truth?
int a; just take this is this a declaration or definition?
int a; if written in global scope is a tentative definition. Which means if no other definitions are available in current compilation unit, treat this as definition or else this is a declaration.
From 6.9.2 External object definitions in C11 specs:
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.
int i4; // tentative definition, external linkage
static int i5; // tentative definition, internal linkage
So you are effectively doing multiple declarations but getting the address and value because of tentative definition rule.
some sources say redeclaration is permitted in c and some say dont
what is the truth?
Redeclaration is permitted in C. But redefinition is not.
Related question: What is the difference between a definition and a declaration?
there are actually many explanation in internet
Prefer a good book instead of internet to get the hold of language. You can choose a good book from:
The Definitive C Book Guide and List
int a is a definition and can be used in place of declaration. A variable can have many declarations but must have only one definition. In case of
int a;
int a;
there are two definition of a in the same scope. Providing linkage to one of them will make your compiler happy
int a;
extern int a;

Declaration or Definition in C

From External Variables Wiki:
If neither the extern keyword nor an
initialization value are present, the
statement can be either a declaration
or a definition. It is up to the
compiler to analyse the modules of the
program and decide.
I was not able to fully grasp the meaning of this statement with respect to C. For example, does it imply that:
int i;
is not necessarily a declaration (as I have been assuming until now), but could be a definition as well (by definition of Definition & Declaration on the same webpage, no puns intended)?
In a nutshell, is the above statement:
a. just a declaration, or
b. declaration + definition?
Reference: Variable declaration and definition
Summary of answers received:
Declaration Definition Tentative Definition Initialized
int i; (inside a block) Yes Yes No No
int i=5; (inside a block) Yes Yes No Yes(to 5)
int i; (otherwise) Yes No Yes Yes(to 0)
extern int i; Yes No No No
All definitions are declarations but not vice-versa.
Assuming it's at file scope it's a 'tentative definition'. From 6.9.2/2 "External object definitions":
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.
This means that it would be valid to also have the following in the translation unit:
int i = 42;
since that declaration has an explicit initializer, it's the definition of the variable i.
As far as if the declaration is in a block scope, the standard says the following (6.2.2/2 "Linkages of identifiers"):
Each declaration of an identifier with
no linkage denotes a unique entity.
...
(paragraph 6) The following
identifiers have no linkage: ... a
block scope identifier for an object
declared without the storage-class
specifier extern.
So in block scope, the declaration would be a definition as well.
The C standard says that
A definition of an identifier is a declaration for that identifier that: for an object, causes storage to be reserved for that object (…)
Definitions encompass declarations, i.e., every definition is necessarily a declaration, so it doesn’t make sense to say that
int i;
is not a declaration. It is a declaration which also happens to be a definition. Or, it is a definition, hence a declaration.
In the context of variables:
A declaration of a variable is a statement which describes how this variable looks like. So:
extern int x;
in global scope translates to: "somewhere in the code, there's a variable called x which has type int and extern linkage. A declaration is necessary before you ever refer to x. (The same goes to function declarations.)
A definition is a statement which creates an instance of this variable. So:
int x;
in global scope creates a single variable of type int with extern linkage. So if you'd put that line in a header, every translation unit including that header would try to create its own copy of x, which is undesirable - that's why we only have declarations in header files. The same goes to functions: if you provide the function body, it's a definition.
Also, formally, every definition is a kind of declaration, as it also has to specify how this variable/function looks like - so if a definition already exists in a given scope, you don't need any additional declarations to use it.
From the C99 spec:
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 this is one case in which a simple declaration without an initializer can be a declaration.
As C uses the terms:
A "definition" creates something (which occupies some sort of memory). It also describes something. This means a "definition" is also a "declaration".
A "declaration" just describes something. The idea is that the compiler needs to know how to build the code that uses the thing defined elsewhere. Later, the linker then links the use to the something.
Declarations allow you to compile code and link it (later) as a separate step.

Resources