Suppose I have a global variable, and I want to assign another variable to it. I've found out that you can assign another value to a global variable inside a function:
int i = 8;
int main(void)
{
i = 9; /* Modifies i */
return 0;
}
However, assignment of the global variable outside of a function does not work!
int i = 8;
i = 9; /* Compiler error */
int main(void)
{
return 0;
}
I get the following error message:
warning: data definition has no type or storage class
warning: type defaults to 'int' in declaration of 'i'
error: redefinition of 'i'
note: previous definition of 'i' was here
int i = 8;
^
Why is this happening?
This is a definition of a global variable, with the optional initialisation to a specific value:
int i = 8;
Note that it is not code which gets ever executed, the variable will just be set up to initially contain the 8. Either consider it "magic" (a helpful model for many things not really defined by the standard) or think of tables with values being copied to memory locations before any code is executed.
This is a piece of code which has no "frame" in which it is executed.
(Or you intend it to be. The compiler is of other opinion, see below.)
i = 9;
There is no function containing it. It is not clear when it should be executed. That is what the compiler does not like.
In C, all code has to be inside a function and will only be executed if that function is called, e.g. from main().
Other language, mostly those which execute "scripts" by interpreting them (instead of code being turned into executeables, e.g. by a compiler) allow to have code anywhere. C is different.
The compiler sees this differently:
i = 9;
it is not inside a function, so it cannot be code
it looks like a variable definition, assuming that you mean it to be an int, i.e. the default
but relying on defaults is not a good idea, so warn about missing type and that the default is used
also, if it is a definition, then it is the second one for i, now that is really wrong, so show an error and fail the compiling
just to be helpful, mention where the first definition of i is
That is how to read the compiler output you have quoted.
Related
In this page I cannot understand why Example 3 throws an error:
// CODE 1:
extern int var;
int main(void)
{
var = 10;
return 0;
}
There are several answers mentioning that var inside main is a local variable. But why would it not be a global variable at the same time. This code below works tough:
// CODE 2:
int var; // global
int main(void)
{
var = 10;
return 0;
}
In the case of multiple files...
... the code below works:
// CODE 3:
// File 1
extern int var;
int main(void)
{
print("%d",var);
return 0;
}
----------------
// File 2
var = 4;
... while this one does not:
// CODE 4:
// File 1
extern int var;
int main(void)
{
print("%d",var);
return 0;
}
----------------
// File 2
int func(int a) {
extern int var;
var = 3;
return 0;
}
So I could not find a meaningful explanation to the behavior of the extern keyword. How do you explain/ interpret that keyword? Also what should I change in the codes to make them work as intended?
In C, every definition is a declaration. Some declarations are definitions, and some are not.
The page you link to, has mistakes. One is it says that “Declaration of a variable or function simply declares that the variable or function exists somewhere in the program, but the memory is not allocated for them.” Actually, that is two mistakes, at least. Per C 2018 6.7 5, “A declaration specifies the interpretation and attributes of a set of identifiers…” This does not necessarily mean any object or function with the declared name actually exists in the program. For example, if we include the <stdio.h> header, the fputc function is declared, but, if we never use it, it might never be linked into the program, and so no such function might exist in the program, even in the file executable file. A declaration that is not a definition only tells the compiler about the name (which we call the identifier); it does not convey information about whether something exists.
A second mistake in that sentence is that it says memory is not allocated for the declared variable or function. This is incorrect because each definition is a declaration. C 2018 6.7 5 continues “… 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…” For example, int x = 3; is a declaration of x, and it is a definition of x, and it causes memory to be allocated for x, but the page you link to says a declaration does not cause memory to be allocated. So the page is wrong.
The rules regarding extern and what is or is not a definition are complicated because C was developed by multiple people doing different things with it. When C was standardized, the committee had to reconcile different practices. As a consequence, there is no single rule for extern.
A note about terminology: A variable is actually two things: an identifier (its name) and an object (the memory that stores a representation of its value).
In your CODE 1, the linked page’s Example 3, extern int var; is a declaration that is not a definition. There is no definition. If an identifier with external linkage is used in an expression, there must be exactly one external definition of it in the program (by C 2018 6.9 5). Since there is no external definition, the linker complains.
There are several answers mentioning that var inside main is a local variable.
If an identifier is declared inside a block, such as the { … } that forms the body of a function, then effects of the declaration are local to that block. If an identifier is declared outside of any function, the effects of the declaration continue through the rest of the file being compiled, except where they are hidden by a nested declaration.
If var is declared outside of any function and before main, and then we use that identifier inside main without declaring it again, that use of var refers to the previous declaration. It does not create or refer to a new local object named var.
But why would it not be a global variable at the same time.
At any one point in source code, an identifier refers to at most one thing.
.. the code below works:
…
// File 2
var = 4
var = 4 is not proper C code because it does not have a semicolon. If it were var = 4;, some compilers might accept this outside a function, but it is archaic. In modern C, it should have a type, such as int var = 4;. That would then be a proper definition of var. If your compiler accepted var = 4; outside a function, you should be aware it is accepting old code, and it would be preferable to use switches to tell the compiler to require modern C code.
Suppose I have a global variable, and I want to assign another variable to it. I've found out that you can assign another value to a global variable inside a function:
int i = 8;
int main(void)
{
i = 9; /* Modifies i */
return 0;
}
However, assignment of the global variable outside of a function does not work!
int i = 8;
i = 9; /* Compiler error */
int main(void)
{
return 0;
}
I get the following error message:
warning: data definition has no type or storage class
warning: type defaults to 'int' in declaration of 'i'
error: redefinition of 'i'
note: previous definition of 'i' was here
int i = 8;
^
Why is this happening?
This is a definition of a global variable, with the optional initialisation to a specific value:
int i = 8;
Note that it is not code which gets ever executed, the variable will just be set up to initially contain the 8. Either consider it "magic" (a helpful model for many things not really defined by the standard) or think of tables with values being copied to memory locations before any code is executed.
This is a piece of code which has no "frame" in which it is executed.
(Or you intend it to be. The compiler is of other opinion, see below.)
i = 9;
There is no function containing it. It is not clear when it should be executed. That is what the compiler does not like.
In C, all code has to be inside a function and will only be executed if that function is called, e.g. from main().
Other language, mostly those which execute "scripts" by interpreting them (instead of code being turned into executeables, e.g. by a compiler) allow to have code anywhere. C is different.
The compiler sees this differently:
i = 9;
it is not inside a function, so it cannot be code
it looks like a variable definition, assuming that you mean it to be an int, i.e. the default
but relying on defaults is not a good idea, so warn about missing type and that the default is used
also, if it is a definition, then it is the second one for i, now that is really wrong, so show an error and fail the compiling
just to be helpful, mention where the first definition of i is
That is how to read the compiler output you have quoted.
This is not a problem, but I'd like to understand the following behaviour:
int main() {
// This does not work
int const a;
a = 50;
// This work
int const a = 50;
}
Why does the compiler throw the following error:
main.c:4:7: error: assignment of read-only variable ‘a’
I don't understand why even the initialization is forbidden. The line 3 has no translation in the assembly language. Does the compiler not detect that the line 4 is the first affectation (translation issue: I meant "assignment")?
EDIT: Ok, so let's say this is how the C language is. But this can be a problem because when I use C89, the declarations must be at the top of the functions and I can't use constant variables because assignments must be placed after the declarations . The only solution is to declare non-const variables or initialize all the variables. I find this "dirty".
I don't understand why even the initialization is forbidden.
The key is in the error message:
error: assignment of read-only variable ‘a’
It isn't an initialization, it is an assignment. An assignment modifies an existing object, and that is not permitted if said object is const.
This, on the other hand, despite using the = syntax, is an initialization:
int const a = 50;
Because it's a constant!
a = 50; is an assignment, not an initialisation.
int const a; essentially sets a to an indeterminant value (which you should never read by the way). Perhaps your compiler will warn you of this if you ask it nicely.
" Does the compiler not detect that the line 4 is the first affectation?"
It could, in this simple case. However the rules are written to cover all cases of initialization.
Compiler looks at one file at a time. A program may be composed of many files. The language allows variables to be declared in one translation unit (file) and used in another.
The rules are written so they take care of all such cases
I want to assign a particular value to a (user defined) global variable in C programming language. When I am doing this from within any other function or main it is fine. But when I am doing it from global space (outside of any function) it is giving the following compilation error:
[expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘.’ token]
Following is a code snippet which causing issue:
#include <stdio.h>
#define MAX_SIZE 5
typedef struct
{
int val[MAX_SIZE];
int top;
}stack_t;
stack_t s;
s.top = -1; // <== Initialization from here is causing compilation error
main()
{
//s.top = -1; < === Initialization from here is fine
printf("s.top =%d\n", s.top);
return 0;
}
But same kind of assignment for integer variables is not giving only warning
#include <stdio.h>
int i,j,k,l;
k=10;
main()
{
printf("i= %d, j=%d k=%d l=%d\n", i, j, k, l);
return 0;
}
Can anyone please tell the reason for this?
The error from the assignment of s.top is not surprising. It is not an initialization but an assignment, and those are different concepts in C. You can't have assignments outside of functions.
The interesting part here is that it looks like you can do an assignment of the integer variable k. But that is an illusion, since in that case it's not an assignment but an initialization!
The line
k = 10;
is interpreted not as an assignment but as a variable definition. A hint to this is that GCC gives the warnings "data definition has no type or storage class" and "type defaults to 'int' in declaration of 'k'". So the line could be written as
int k = 10;
As Matt wrote in a comment below, leaving out the data type like this seems to be a GCC extension, and not something that the standard allows.
(By the way, do turn on warnings in your compiler, and pay attention to them!)
But wait, wasn't there already a definition of k on the line above, and you can't have more than one definition, can you?
First, remember that C makes a distinction between definitions and declarations. A definition of a variable is when you "create" the variable, and optionally give it an initial value. A declaration is when you just tell the compiler that the variable exists, and its name and data type, but the definition is elsewhere. You can have both a definition and one or more declarations of the same variable. For example:
int xxx = 10; // This is the definition of xxx
int xxx; // This is a declaration of xxx
int xxx; // Another delaration of xxx
But sometimes the compiler can't determine if what it sees is a declaration or a definition, and then it is interpreted as a "tentative definition", or in other words "perhaps a definition, perhaps just a declaration, we'll decide later". For example:
int yyy;
Is that a definition of the variable yyy (without an initial value), or is it just a declaration, where the definition will be found elsewhere? The compiler doesn't know, so it waits to decide, and calls this a tentative definition.
When the compiler sees your first declaration of k (along with the other variables i, j and l) it is interpreted as a tentative definition, and when the later definition is found, that tentative definition of k will be decided to be a declaration, not a definition.
C code has to be inside a function. You can declare a global outside of a function but you can't write an assignment statement outside of a function. That is you can set the initial value as part of declaring the struct but you can't then change it. Here your declaration is only the "stack_t s;" line.
Everything in C ends up compiling to symbols in a binary format (an example would be the ELF format). Symbols have names, so functions are named chunks of code, and globals are named chunks of data. There are no "free floating" chunks in the compiled binary, everything has to go under a name.
In the C model, code floating around outside of a function doesn't make sense because C doesn't have a place where it would run that code. C never runs a file in the way that bash or Python or javascript does; it only runs binaries. So it only runs named
functions. The files are only known at compile time not runtime.
Initializing the outside the main is reason for that error. You can do that using like this.
stack_t s={.top=-1};
It will allow you to do the initialization while declaring. Refer this link. or this It can be useful.
There are differences between assignment and initialization. You should note that, assignment can't be done outside of a function. The statement
s.top = -1;
is an assignment not an initialization.
C99 and latter provides designated initialization of structs and arrays. So, you can initialize only the top member of struct s as
stack_t s = { .top = -1 };
and other members will be initialized to 0 by the compiler.
In the global space you can only initialize and declare the variables but cannot assign the value to variables. In your code you are assigning the value to member of struct so its throwing error and same holds true for integers for your below code.
Try the below code in the global space and it works fine:
typedef struct
{
int val[MAX_SIZE];
int top;
}stack_t;
stack_t s={{},-1};
main()
{
printf("s.top=%d",s.top);
return 0;
}
The following code is similar to that of question Is there a difference between initializing a variable and assigning it a value immediately after declaration? downvoted twice, so I am at risk ;-)
short i;
i = 2;
It does not compile with MinGW and -std=c99 -- why? The first line is a declaration of identifier i, not a definition of an object. However, the identifier has file scope and thus external linkage by default. It may be declared and defined elsewhere. The second line could be an assignment to that object. But gcc complains about a missing type or storage class and --after guessing the type as int-- about a type conflict.
You say that short i; has file scope, which implies to me that it (edit: and the subsequent i = 2;) is outside a function. Outside a function, i = 2; on its own is complete nonsense; as a statement, it cannot appear outside a function. (edit) As statements cannot appear outside functions, the "assignment" must be a definition. In old C code, a definition without a storage class was an int definition, so your code is equivalent (under those rules, which it looks like GCC is applying) to:
short i;
int i = 2;
which of course is complete nonsense to a C compiler. (end edit)
You can get more-or-less the effect you're after by defining and initializing:
short i = 2;
This does not work if you merely wish to declare an external variable; in that case, put the initialization in the file with the definition, or in one of your functions (as below).
extern short i;
int main(int argc, char **argv) { i = 2; /* more code */ }