Is redeclaration of global objects legal or illegal in C? [duplicate] - c

I read from a book about tentative defination that,
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
Please explain what the above statement means.
Also, the difference between Declaration and Definition? I got mixed up due to this. :(
And why doesn't this program give an error:
#include <stdio.h>
int a; //Tentative definition
int a; //similarly this declaration too.
int main() //not getting any error with this code why its so?
{
printf("hi");
}
Also, what is wrong with this code:
#include<stdio.h>
printf("Hi");
int main(void){
return 0;
}

A variable declaration says, "there is a variable with the following name and type in the program".
A variable definition says, "Dear Mr. Compiler, please allocate memory for a variable with the following name and type now."
So there can be multiple declarations for the same variable, but there should be only one definition.
In C, pure declarations (that are not also definitions) are preceded with the keyword extern. So, since you do not have this keyword in your first example, what you have is two definitions. On its face, this would seem to be a problem (and is in fact an error in C++), but C has a special "tentative definition" rule which allows multiple definitions for the same variable in the same translation unit so long as they all match and at most one has an initializer. The C compiler, behind the scenes, combines all of the tentative definitions into a single definition.
Had you attempted to initialize both definitions, like this:
int a = 1;
int a = 2;
Then you would have had an error.
Your second question is more straightforward. In C, you simply cannot have executable statements outside of the body of a function. It's just not allowed. Think about it: when would you expect it to run if it were allowed?

The first works because both your definitions of a are tentative, which can be duplicated as often as you see fit. At the end of the translation unit, no non-tentative definition has been seen, so what you've specified for attributes is combined with defaults to give a final definition of a, so it'll have external linkage, static storage duration, and be initialized to 0.
The problem with the second has nothing to do with tentative definitions. Your printf("Hi"); needs to be inside a function to work -- it's not a declaration or a definition (tentative or otherwise); it's just not allowed there.

Related

Does the compiler automatically add an "extern" to a global variable that is not assigned a value in Programe language C? [duplicate]

This question already has answers here:
In C, is it valid to declare a variable multiple times?
(1 answer)
In C,why is multiple declarations working fine for a global variable but not for a local variable?
(3 answers)
Closed last year.
So far I have understood the following:
A variable declaration is the declaration of a type and name of a variable without allocating memory space for it.
A variable definition means that the variable is declared and memory space is allocated for it.
So it has nothing to do with the initialization of the variable, whether you speak of a definition or a declaration.
In C, a declaration is always a definition e.g. if one write int i;.
But there is one exception. If you write extern int i; no memory space is allocated, only the variable is declared.
So int i; is always declaration and definition at the same time. But extern int i; is just declaration.
Is it true that in C you can declare a variable as often as you want, but you can only define the variable once?
I ask because I've tried the following and the compiler results confuse me. I use gcc and don't set the -std flag.
Neither this program:
int i;
int i;
void main(void){
i = 2;
}
nor this program:
int i=0;
int i;
void main(void){
i = 2;
}
lead to problems. The compiler compiles both without error. I would have expected since I didn't use the "extern" keyword here that the compiler would say something like "error: multiple definition".
But it doesn't give an error message. Is it possible that the compiler automatically writes an "extern" before all global defined "int i;" if I don't initialize them at the same time?
Isn't it then superfluous for the programmer to ever use the extern keyword for variables since the compiler will do that automatically anyway?
I think my considerations are confirmed by the following behavior. The following programs return errors:
int i;
i=0;
void main(void){
i = 2;
}
leads to:
"warning: data definition has no type or storage class
i=0;
warning: type defaults to 'int' in declaration of 'i' [-Wimplicit-int]"
and
float i;
i=0;
void main(void){
i = 2;
}
leads to:
"warning: data definition has no type or storage class
i=0;
warning: type defaults to 'int' in declaration of 'i' [-Wimplicit-int]
error: conflicting types for 'i'
note: previous declaration of 'i' was here
float i;"
So to me again it looks like there is an implicit "extern" before the first int i; respectively float i; is written because they are not assigned a value. As a result, no storage space is allocated for i.
But there is no other file in which storage space is allocated for i. Therefore there is no definition for i and the compiler therefore thinks in the 2nd line that i should be defined here.
Therefore there are no problems with the 1st program because the automatic type assignment fits, but with the 2nd program it no longer fits, which is why an error is returned.
The following program also throws an error:
void main(void){
int i;
int i;
}
If I write the declaration (and thus also the definition) in a scope, the compiler returns the following error message.
"error: redeclaration of 'i' with no linkage int i;
note: previous declaration of 'i' was here int i;"
I can only explain it again with the fact that the compiler does not automatically set an "extern" before a variable that is not a global variable and therefore there are 2 definitions here.
But then I ask myself why is it called redeclaration and not redefinition or multiple definition?
It would be very nice if someone could confirm my assumptions or enlighten me on how to understand it correctly. Many Thanks!
A variable declaration is the declaration of a type and name of a variable without allocating memory space for it.
Even if memory is reserved for an object, it a declaration. We do not exclude definitions from declarations; there are declarations that are definitions and declarations that are not definitions.
The declaration x = 3; causes memory to be reserved for x, but it also makes the name and type of x known, so it declares x.
So int i; is always declaration and definition at the same time.
Not quite. Inside a function, int i; is a definition. Outside of a function, int i; is a tentative definition. This is a special category that was necessary due to the history of C development. The language was not designed all at once with foresight about how it would be used. Different implementors tried different things. When a standard for the C language was developed, the committee working on it had to accommodate diverse existing uses.
When there is a tentative definition, the program can still supply a regular definition later in the translation unit. (The translation unit is the source file being compiled along with all the files included in it.) If the program does not supply a regular definition by the end of the translation unit, then the tentative definition becomes a regular definition as if it had an initializer of zero, as in int i = 0;.
Some C implementations treat multiple tentative definitions of an identifier in different translation units as referring to the same object. Some C implementations treat them as errors. Both behaviors are allowed by the C standard.
Is it true that in C you can declare a variable as often as you want, but you can only define the variable once?
Not always. Variables with no linkage (declared inside a function without static or extern) may not be declared more than once. (An identical declaration can appear inside a nested block, but this declares a new variable with the same name.)
Repeated declarations must have compatible types, and there are additional rules about which repeated declarations are allowed. For example, an identifier may not be declared with static after it has been declared with extern.
The compiler compiles both without error.
As described above, int i; outside a function is a tentative definition. Initially, it acts only as a non-definition declaration. So it may be repeated, and it may be replaced by a regular definition.
So to me again it looks like there is an implicit "extern" before the first int i;
No, there is not. int i; is a tentative definition, and it has nothing to do with the error messages you are getting. The error messages “data definition has no type or storage class” and “type defaults to 'int' in declaration of 'i'” are from the i=0;. This is a statement, not a declaration, but the C grammar does not provide for statements outside of functions. Outside of functions, the compiler is looking for only declarations. So it expects to see a type, as in int i=0;. The first message tells you the compiler does not see a type or a storage class. The second message tells you that, since it did not see a type, it is assuming int. This is a relic of old behavior in C where the int type would be taken as a default, so it could be left off. (Do not use that in new C code.)
The following program also throws an error:
Inside a function, int i; is a definition, so two of them causes multiple definitions of i.

Variable Declaration and Scope in C [duplicate]

This question already has answers here:
How do I use extern to share variables between source files?
(19 answers)
Closed 3 years ago.
There is a code snippet as below,
int var1;
extern int var2;
It is a multiple choice.
The answer is, First statement declares and defines var1, but second statement only declares var2.
But I think it is supposed to be "Both statements only declare variables, don’t define them."
Which one is correct?
This might help. source
Declaration of a variable is for informing to the compiler the
following information: name of the variable, type of value it holds
and the initial value if any it takes. i.e., declaration gives details
about the properties of a variable. Whereas, Definition of a variable
says where the variable gets stored. i.e., memory for the variable is
allocated during the definition of the variable.
In C language definition and declaration for a variable takes place at
the same time. i.e. there is no difference between declaration and
definition. For example, consider the following declaration
int a;
Here, the information such as the variable name: a, and data type:
int, which is sent to the compiler which will be stored in the data
structure known as symbol table. Along with this, a memory of size 2
bytes(depending upon the type of compiler) will be allocated.
Suppose, if we want to only declare variables and not to define it
i.e. we do not want to allocate memory, then the following declaration
can be used
extern int a;
In this example, only the information about the variable is sent and
no memory allocation is done. The above information tells the compiler
that the variable a is declared now while memory for it will be
defined later in the same file or in different file.
The answer depends on several factors.
If these declarations
int var1;
extern int var2;
are block scope declarations then the first declaration is also a definition and the second declaration is just a declaration without a definition. The variable var1 is not initialized that is it has an indeterminate value.
If these declarations are declarations of the file scope then whether the first declaration is a definition is defined by whether the declaration has an external definition.
If the declaration does not have an external definition then this declaration named as tentative definition is a definition and have an implicit initializer equal to 0.
As for the second declaration then again whether it is a definition depends on whether there is an external definition or not. If there is no external definition then the linker can either create the definition or issue an error.
In C a declaration with the file scope is also a definition when either it has an initializer or it is a tentative definition without an external definition.
Actually, the extern keyword extends the visibility of the C variables and C functions.
Declaring vs Defining a variable?
Declaration of a variable/function simply declares that the variable/function exists somewhere in the program but the memory is not allocated for them.
Snippet 1:
extern int var;
int main(void)
{
var = 10;
return 0;
}
Snippet 1 throws an error in compilation. Because var is declared but not defined anywhere. Essentially, the var isn’t allocated any memory. And the program is trying to change the value to 10 of a variable that doesn’t exist at all.
Snippet 2:
#include "somefile.h"
extern int var;
int main(void)
{
var = 10;
return 0;
}
Supposing that "somefile.h" has the definition of var. Snippet 2 will be compiled successfully.

Why can I redefine a variable in a C program? [duplicate]

I read from a book about tentative defination that,
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
Please explain what the above statement means.
Also, the difference between Declaration and Definition? I got mixed up due to this. :(
And why doesn't this program give an error:
#include <stdio.h>
int a; //Tentative definition
int a; //similarly this declaration too.
int main() //not getting any error with this code why its so?
{
printf("hi");
}
Also, what is wrong with this code:
#include<stdio.h>
printf("Hi");
int main(void){
return 0;
}
A variable declaration says, "there is a variable with the following name and type in the program".
A variable definition says, "Dear Mr. Compiler, please allocate memory for a variable with the following name and type now."
So there can be multiple declarations for the same variable, but there should be only one definition.
In C, pure declarations (that are not also definitions) are preceded with the keyword extern. So, since you do not have this keyword in your first example, what you have is two definitions. On its face, this would seem to be a problem (and is in fact an error in C++), but C has a special "tentative definition" rule which allows multiple definitions for the same variable in the same translation unit so long as they all match and at most one has an initializer. The C compiler, behind the scenes, combines all of the tentative definitions into a single definition.
Had you attempted to initialize both definitions, like this:
int a = 1;
int a = 2;
Then you would have had an error.
Your second question is more straightforward. In C, you simply cannot have executable statements outside of the body of a function. It's just not allowed. Think about it: when would you expect it to run if it were allowed?
The first works because both your definitions of a are tentative, which can be duplicated as often as you see fit. At the end of the translation unit, no non-tentative definition has been seen, so what you've specified for attributes is combined with defaults to give a final definition of a, so it'll have external linkage, static storage duration, and be initialized to 0.
The problem with the second has nothing to do with tentative definitions. Your printf("Hi"); needs to be inside a function to work -- it's not a declaration or a definition (tentative or otherwise); it's just not allowed there.

C - In what circumstances does the external declaration become a definition?

From C99 standard 6.2.3:
If the declaration of an identifier of an object has file scope and no storage-class specifier, its linkage is external.
and 6.7
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;99)
— for an enumeration constant or typedef name, is the (only) declaration of the identifier.
Unfortunately, I haven't found any further description on when the compiler shall regard the external declaration as a definition (which means the type must be complete and storage size is calculated).
So I did some experiments. First I noticed that:
struct A a;
int main() {
}
Is invalid, gcc says the type A is incomplete and it doesn't know how to allocate the storage for a.
However, interestingly, we have the following valid code:
struct A a;
int main() {
}
struct A {int x;};
It's also reasonable since type A is completed at the end of the file. From two examples above, we can deduce that external declaration is checked at the end of file scope. (Still don't know where does the standard say about this)
However, array declaration is exceptional. The modified code is not longer valid:
struct A a[1];
int main() {
}
struct A {int x;};
And C99 standard does talk about this, it says elements of an array must be of completed type. So question comes about: is struct A a[1] a definition or a declaration? Don't be hasty to answer it. Check the following examples.
Here we have two files: a.c and b.c. In a.c:
#include <stdio.h>
int arr[10];
void a_arr_info() {
printf("%lu at %lx\n", sizeof arr, (size_t)arr);
}
while in b.c:
#include <stdio.h>
int arr[20];
void b_arr_info() {
printf("%lu at %lx\n", sizeof arr, (size_t)arr);
}
int main() {
a_arr_info();
b_arr_info();
}
The result is astonishing. The output shows that arr in both files refers to the same address. Which can be understood because arr are both in file scope, thus they're external linkage. The problem is, they have different size. In what file did the compiler take the declaration as definition and allocate the memory?
Why do I ask about this? Because, um, I'm working on a simplified C compiler project (course homework). So it might be important for me to figure it out. Although the homework does not go as far as this, I'm quite curious and would like to know more. Thanks!
It is called a tentative definition
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 any compilation unit (.o file) that has such a tentative definition realizes the object. Linking two such units together has undefined behavior, you should usually encounter a "multiply defined symbol" error. Some compiler/linkers just do it, you have to ensure that such symbols have same size and type.

About Tentative definition

I read from a book about tentative defination that,
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
Please explain what the above statement means.
Also, the difference between Declaration and Definition? I got mixed up due to this. :(
And why doesn't this program give an error:
#include <stdio.h>
int a; //Tentative definition
int a; //similarly this declaration too.
int main() //not getting any error with this code why its so?
{
printf("hi");
}
Also, what is wrong with this code:
#include<stdio.h>
printf("Hi");
int main(void){
return 0;
}
A variable declaration says, "there is a variable with the following name and type in the program".
A variable definition says, "Dear Mr. Compiler, please allocate memory for a variable with the following name and type now."
So there can be multiple declarations for the same variable, but there should be only one definition.
In C, pure declarations (that are not also definitions) are preceded with the keyword extern. So, since you do not have this keyword in your first example, what you have is two definitions. On its face, this would seem to be a problem (and is in fact an error in C++), but C has a special "tentative definition" rule which allows multiple definitions for the same variable in the same translation unit so long as they all match and at most one has an initializer. The C compiler, behind the scenes, combines all of the tentative definitions into a single definition.
Had you attempted to initialize both definitions, like this:
int a = 1;
int a = 2;
Then you would have had an error.
Your second question is more straightforward. In C, you simply cannot have executable statements outside of the body of a function. It's just not allowed. Think about it: when would you expect it to run if it were allowed?
The first works because both your definitions of a are tentative, which can be duplicated as often as you see fit. At the end of the translation unit, no non-tentative definition has been seen, so what you've specified for attributes is combined with defaults to give a final definition of a, so it'll have external linkage, static storage duration, and be initialized to 0.
The problem with the second has nothing to do with tentative definitions. Your printf("Hi"); needs to be inside a function to work -- it's not a declaration or a definition (tentative or otherwise); it's just not allowed there.

Resources