I have the below code and I see that the two variables have been assigned with same address. Both the variables are completely different type . Is there anyway I can void this ? And under what circumstances does the same memory gets allocated to both the variables .
static int Sw_Type [];
static BOOL Sw_Update;
void main()
{
int i;
int bytes = 3;
if (Sw_Update!= TRUE)
{
for(i = 0; i< bytes ;i++)
{
Sw_Type [i] = *Ver_Value;
Ver_Value++;
}
Sw_Update= TRUE;
}
}
This is a snippet of my code and "Ver_Value" is a structure which gets assigned in different function.
So the problem I am seeing is , when Sw_Update gets updated, Sw_Type [1] is getting updated and I see these two have same memory address.
static int Sw_Type []; constitutes a tentative definition, per C 2018 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.
Since your program provides no non-tentative definition, it is as if it ended with static int Sw_Type [] = { 0 };. (In case it is not clear from the text quoted above that the result is indeed an array of one element, it is made clear by Example 2 in paragraph 5 of the same clause.)
Thus, Sw_Type is an array of one int. It contains only the element Sw_Type[0]. The behavior of accessing Sw_Type[1] is not defined by the C standard. From the observations you report, it appears as if Sw_Update follows Sw_Type in memory, and accessing Sw_Type[1] results in modifying Sw_Update. This behavior is of course not reliable.
To make Sw_Type larger, you must declare a size for it, as with static int Sw_Type[4];.
Note: 6.9.2 3 says “If the declaration of an identifier for an object is a tentative definition and has internal linkage, the declared type shall not be an incomplete type.” While this might be read as applying to the declared type in each declaration that is a tentative definition, I think it might be intended to apply to the declared type of the object once its composite type is fully resolved at the end of the translation unit. Experimentally, Clang is okay with accepting an incomplete type at first and completing it later.
So the problem I am seeing is , when Sw_Update gets updated, Sw_Type [1] is getting updated and I see these two have same memory address.
There is no Sw_Type [1]. Only an array with two or more elements has a second entry, and Sw_Type is not an array with two or more elements. Accessing an array out of bounds can certainly stomp on other objects.
Related
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.
This question already has answers here:
About Tentative definition
(2 answers)
In C,why is multiple declarations working fine for a global variable but not for a local variable?
(3 answers)
Closed 5 years ago.
/*How does this code compiles and executes in C?*/
#include <stdio.h>
int x= 9; //Varaible initialization
int x; //Variable declaration, same name
int main(void) {
printf("%d", x); //output: 9
return 0;
}
There should be an error while compilation as same variable is used. How come the code compiles?
From standard 6.9.2p2 you can know about this - this is known as tentative definition.
From here
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. If an actual external definition is found earlier or later in the same translation unit, then the tentative definition just acts as a declaration.
int i1 = 1; // definition, external linkage
int i1; // tentative definition, acts as declaration because i1 is defined.
So from these two references it is clear that the second one merely boils down a declaration or valid tentattive definition on standard words and the value it takes is the one assigned that is 1.
Sane goes here for you with the value of x being 9.
You can declare a global variable or function as many times as you wish. But you must have only one definition. The first line assigns the variable a value, so it is a declaration and definition combined. The second line does not assign a value, so it is only a declaration.
In Global scope two variable with same name is possible but one should be un-intialized(weak symbol) and another one should be initialized(strong symbol).
int x= 9; /* strong symbol i.e declaration with definition*/
int x; /* weak symbol i.e only declaration */
while choosing among two, priority is given two strong symbol.
Note : compiler won't allow to have two strong symbol at a time, that would be a re-definition of variable.
The second one is not a definition. It's a declaration.
From the ISO C standard draft N1570, Section 6.9.2:
1 If the declaration of an identifier for an object has file scope and an initializer, the declaration is an external definition for the identifier.
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.
So when you write
int x;
in file scope, it's not necessarily a definition. It's a declaration, which is fine to be repeated.
This is called tentative definition in C. See more here, here and here.
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.
I tried these three versions of a small program and I got some interesting results. Can anyone please help me understand compiler behaviour in each case.
version 1.0
int A;
int A;
int A;
int main ()
{
return 0;
}
Result: Got compiled with one copy of A in BSS.
Version 2.0
int main ()
{
int A;
int A;
int A;
return 0;
}
Result: Failed to compile with complaining for re-declaration.
Version 3.0
int A;
int main()
{
static int A;
return0;
}
result: Compiled with two copy of A in BSS. one is A and another a.<some numeric tag>.
In your first example, int A; is a tentative definition: a declaration of an identifier at file scope without an initializer and either without a storage class or a static storage class. You can have multiple ones, and they will all refer to the same variable:
The standard says:
(ISO/IEC 9899:1999 6.9.2)
A declaration of an identifier for an object that has file scope without an initializer, and without a storage-class specifier or with a 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 definitions 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.
In your second example, A is not of file scope. It's a local variable and it's not a tentative definition, so you can only have one.
In your third example, the A at file scope is a different variable than the A inside main(), as they have different scopes. Just because the second A is static doesn't change its scope; the identifier is still only visible from inside main(). This is a case of variable shadowing, where a variable in one scope has the same identifier as a variable in an enclosing scope (in this case the main() scope vs the file scope.) The fact the the A at file scope happens to be a tentative definition does not affect the A inside main().
I understand this:
int i = 3; // declaration with definition
It tells the compiler to:
Reserve space in memory to hold integer value.
Associate name with memory location.
Store the value 3 at this location.
But what does this declaration tell the compiler:
int i; // declaration
The declaration tells the compiler to reserve space for the variable i and associate the name i with that space (your points 1. and 2.).
If i is a global variable it is initialized to 0.
If it is local the value of i is undefined (probably garbage, ie. some random value) and you should assign to it before reading it.
There are two cases: at file scope (i.e. for a global declaration), and in a function.
In a function, the declaration int i; does two things: it declares a variable called i whose type is int, and it reserves some storage in memory to put a value of type int. What it does not do is give the variable a value. The storage used by i will still contain whatever garbage was there before. You need to initialize the variable, i.e. assign a value to it, before you can read a value from it. Good compilers will warn you if you don't initialize the variable.
At file scope, int i also declares a variable called i. The rest depends on other things: this is known as a tentative definition. You can have multiple such declarations in your file. At most one of these is allowed to have an initializer, making it a full-fleged definition. If none of the declarations of i at file scope have an initializer, the declaration is also a definition, and there is an implicit initialization to 0. Thus:
int i;
/* ... more code ...*/
int i;
is valid, and i will be initialized to 0 (assuming these are the only declarations of i at file scope). Whereas:
int i;
int i = 3;
is also valid, and i will be initialized to 3 when the program starts.
In practice, at file scope, there's often a difference between leaving the initialization implicit and explicitly initializing to 0. Many compilers will store an explicit 0 in the binary, but let the operating system initialize implicit zeroes automatically when the program is loaded. Don't worry about this unless you have a large global array (which shouldn't happen often) or you work on tiny embedded systems.
It says to reserve space for an integer called i. As far as what is in there is up to the compiler and is undefined.
It does the same thing as your previous declaration:
allocates space on the stack for the integer
the compiler associates a name with the space (your running program won't do this, necessarily)
the integer is not initialized.
Others have pretty much answered the question, but I will mention two points that (I think ) haven't been mentioned so far:
int i;
defines i to be an int, with garbage in it (unless i is "global"). Such garbage might be a trap representation, which means that using it could be "bad":
A trap representation is a set of bits which, when interpreted as a value of a specific type, causes undefined behavior. Trap representations are most commonly seen on floating point and pointer values, but in theory, almost any type could have trap representations. An uninitialized object might hold a trap representation. This gives the same behavior as the old rule: access to uninitialized objects produces undefined behavior.
Also, int i; could also be a tentative definition, which means that you're telling the compiler: "i is an int, and I will define it later. If I don't, then define it for me.". Here is a very good explanation of why C has tentative definitions.
There are three kinds of memory for objects:
1) external (often called "global" but that really refers to scope). Objects here are created before running the program; 2) stack (created during run time); 3) heap (eg malloced).
"int i;" either creates the object in the external memory or on the stack. If it's in a function, it's created on the stack (if "static" isn't also used.
Objects created in external memory are initialized to zero if they are not explicitly initialized (e.g, "int i = 3";
You can create an external object in a function by using the "static" keyword.
int a; // external memory with "global" scope. Initialized to 0 implicitly.
static int b; // external memory with file (module) scope. Initialized to 0 implicitly.
int c = 3; // external memory initialized to 3.
f()
{
int d; // created on the stack. Goes away when the block exits. Filled with random trash because there is no initialization.
int e = 4; // stack object initialized to 3.
static int f; // "f" is external but not global. Like all externals, it's implicitly initialized to zero.
static int g = 3; // An external like f but initialized to 3.
}