I have compiled following program using gcc prog.c -Wall -Wextra -std=gnu11 -pedantic command on GCC compiler. I wondered, it is working fine without any warnings or errors.
#include <stdio.h>
int main(void)
{
for (int i = 0; i == 0; i++)
{
printf("%d\n", i);
long int i = 1; // Why doesn't redeclaration error?
printf("%ld\n", i);
}
}
Why compiler doesn't generate redeclaration variable i error?
From standard §6.8.5.5 (N1570)
An iteration statement is a block whose scope is a strict subset of
the scope of its enclosing block. The loop body is also a block whose
scope is a strict subset of the scope of the iteration statement.
Emphasis added
In C language, the scope of statement is nested within the scope of for loop init-statement.
According to Cppreference :
While in C++, the scope of the init-statement and the scope of
statement are one and the same, in C the scope of statement is nested
within the scope of init-statement.
According to stmt:
The for statement
for ( for-init-statement conditionopt ; expressionopt ) statement
is equivalent to
{
for-init-statement
while ( condition ) {
statement
expression ;
}
}
except that names declared in the for-init-statement are in the same declarative-region as those declared in the condition,
and except that a continue in statement (not enclosed in another
iteration statement) will execute expression before re-evaluating
condition.
You have to set -Wshadow to get warnings on shadowed variables. Variable shadowing is allowed in C.
But this is an edge case. A var declared in the head of a for construction is not outside the brackets, because it has no scope after the construction.
This is not equivalent:
int i;
for( i = 0; …)
{ … }
// is is still in scope but wouldn't if declared in the head of for
But, it is not inside the brackets, too.
for( i = 0; …)
{
int i; // this would be strange, because i is used before it is declared.
…
}
The best approximative replacement of the code is this:
{
int i;
for( i = 0; …)
{
…
}
} // i loses scope
So it is no redeclaration, but a shadowing declaration inside the loop's body.
Why compiler doesn't generate redeclaration variable i error?
From C Standards#6.2.1p4 Scopes of identifiers
Every other identifier has scope determined by the placement of its declaration (in a declarator or type specifier). If the declarator or type specifier that declares the identifier appears outside of any block or list of parameters, the identifier has file scope, which terminates at the end of the translation unit. If the declarator or type specifier that declares the identifier appears inside a block or within the list of parameter declarations in a function definition, the identifier has block scope, which terminates at the end of the associated block. If the declarator or type specifier that declares the identifier appears within the list of parameter declarations in a function prototype (not part of a function definition), the identifier has function prototype scope, which terminates at the end of the function declarator. If an identifier designates two different entities in the same name space, the scopes might overlap. If so, the scope of one entity (the inner scope) will end strictly before the scope of the other entity (the outer scope). Within the inner scope, the identifier designates the entity declared in the inner scope; the entity declared in the outer scope is hidden (and not visible) within the inner scope.
From C standards#6.8.5p5 Iteration statements
An iteration statement is a block whose scope is a strict subset of the scope of its enclosing block. The loop body is also a block whose scope is a strict subset of the scope of the iteration statement.
So, in this code:
for (int i = 0; i == 0; i++)
{
printf("%d\n", i);
long int i = 1; // Why doesn't redeclaration error?
printf("%ld\n", i);
}
the scope of identifier with name i is overlapping and in this name space, the i declared in for (int i = 0; i == 0; i++) has outer scope and the one declared within loop body long int i = 1; has inner scope.
Within the loop body, after this statement:
long int i = 1;
the i declared in the outer scope is not visible and printf() printing the value of i visible in the inner scope which is 1.
This behavior is also known as Variable Shadowing which occurs when a variable declared within a certain scope has the same name as a variable declared in an outer scope.
C language allows variable shadowing and that's why the compiler does not throw any error for this. However, in gcc compiler, if you use -Wshadow option you will get a warning message - declaration shadows a local variable.
For further verification i checked this code in visual studio 2008 for the prog.c file. I found that the compiler does give error in the line for (int i = 0; i == 0; i++) . The compiler expects declaration of i to be in the beginning of the program itself. This behavior is correct for a C file. If the declaration is moved to the beginning of the program then there are no errors as expected. All scope related issues are solved.
If i try this code as prog.cpp file, then the compiler does give an error for redeclaration. This is also an expected behavior.
So i conclude this has to do with the gcc compiler, does any flag/parameters that is used for compiling/building the exe results in this behavior for the gcc compiler.
Can rsp post the make file details for further verification?
Related
I had such a question:What is the difference between
int i;
for(i = 0; i < n; i++)
and
for(int i = 0; i < n; i++)
Does this influence memory and time?
C 2018 6.2.1 2 says:
For each different entity that an identifier designates, the identifier is visible (i.e., can be used) only within a region of program text called its scope…
6.2.1 4 says:
Every other identifier [paragraph 3 discussed labels] has scope determined by the placement of its declaration (in a declarator or type specifier)… If the declarator or type specifier that declares the identifier appears inside a block or within the list of parameter declarations in a function definition, the identifier has block scope, which terminates at the end of the associated block…
Which portions of C source code form blocks is stated individually in several places.
6.8.2 1:
A compound statement [source code inside { and }] is a block.
6.8.4 3:
A selection statement [if, if … else, and switch] is a block whose scope is a strict subset of the scope of its enclosing block. Each associated substatement is also a block whose scope is a strict subset of the scope of the selection statement.
6.8.5 5:
An iteration statement [while, do … while, and for] is a block whose scope is a strict subset of the scope of its enclosing block. The loop body is also a block whose scope is a strict subset of the scope of the iteration statement.
Thus for (int i = 0; i < n; i++) declares an i whose scope is limited to the for statement. This i cannot be used after the for statement.
In contrast, the int i; before the for statement declares an i that can be used throughout the block it is in, which is the { … } that it is enclosed in.
Assuming you have written this code in the main function,
int i;
for(i = 0; i < n; i++)
In the case above, i is a local variable of the main function. If the value of i is updated in the loop it will remain updated even after the loop ends. i is not destroyed after the for loop. This is useful in some programs where you need the value of i after the loop for later use.
for(int i = 0; i < n; i++)
In the case above, i is a local variable of the for loop. i will be destroyed once the loop is over.
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.
{
int i;
for(i=0;i<5;i++)
{
int i=10;
printf("%d",i);
}
}
I have two questions
Why is there no redeclaration error for i?
why output will be 10 5 times and not 10 1 time?
It all has to do with the scope of an identifier. An identifier is simply a name given to an entity (object, function, typedef name and so on) in C and, as per C11 6.2.1 /1:
The same identifier can denote different entities at different points in the program.
The scope of an entity is described in /2 of that section:
For each different entity that an identifier designates, the identifier is visible (i.e., can be used) only within a region of program text called its scope.
And /4 covers your specific case:
If an identifier designates two different entities in the same name space, the scopes might overlap. If so, the scope of one entity (the inner scope) will end strictly before the scope of the other entity (the outer scope).
In other words, something like:
{
int i = 42;
printf ("%d ", i);
{
int i = 17;
printf ("%d ", i);
}
printf ("%d\n", i);
}
is perfectly valid, and will print 42 17 42. That's because the identifier i inside the inner block is in its own scope, which ends at the first closing brace.
In your particular case, you can think of it as:
{
int i; \
for(i=0;i<5;i++) > outer i scope
{ /
int i=10; \
printf("%d",i); > inner i scope
} /
}
The inner int i=10 effective hides the outer i for the duration of the body of the for loop. That's why it prints a lot of 10s rather than 0..4.
The scope of the inner i finishes at the closing brace of the for loop body so that, when the continuation condition of the for loop is checked, it once again sees the outer i. That's why it loops five times rather than once.
In your code
int i; is in outer block scope.
int i=10; is in the inner block scope for the for loop
If we visualize the same, we can come up with something like'
{ //---------------------------|
int i; |
for(i=0;i<5;i++) |
{ |
int i=10; //-------| inner scope |> Outer scope
printf("%d",i); //-------| |
} |
} //----------------------------|
The case here is, the inner i will shadow the outer i. These two are considered seperate variable (based on their scope).
In other words, the i which is defined and present inside the block (inner scope) will have more preference (over the variable in outer scope). So, the inner i value will get printed.
OTOH, the loop counter variable i remains at the outer scope. It's value is not altered through the assignement inside the block. So, rightly it loops for 5 times, as asked.
Related: From C11 standard, chapter §6.2.1, paragraph 4,
..[..].. If an identifier designates two different entities in the same name
space, the scopes might overlap. If so, the scope of one entity (the inner scope) will end strictly before the scope of the other entity (the outer scope). Within the inner scope, the identifier designates the entity declared in the inner scope; the entity declared in the outer scope is hidden (and not visible) within the inner scope.
So, to answer your questions,
Why is there no redeclaration error for i?
Because two is are treated as seperate variable, despite being named same.
why output will be 10 5 times and not 10 1 time?
Because, the outer i, used as the counter, is not changed from inside the loop, only the loop increment condition is altering that value.
You aren't re-declaring i since the second declaration of i ( 'int i =10' ) is inside a loop . That's means that in your example the variable is destroyed and recreated for each iteration of the loop .
The scope of variables created in any compound statement is limited to the compound statement itself .
Ps : If you wanted to stop the loop by changing the value of i
{
int i;
for(i=0;i<5;i++)
{
i=10;
printf("%d",i);
}
}
If you ask your compiler nicely (gcc -Wshadow) it will warn you
echo -e '#include <stdio.h>\nvoid f(void) { int i; for (i = 0; i < 5; i++) { int i = 10; printf("%d", i); } }' | gcc -Wshadow -xc -c -
<stdin>: In function 'f':
<stdin>:2:53: warning: declaration of 'i' shadows a previous local [-Wshadow]
<stdin>:2:20: note: shadowed declaration is here
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;
}
Is there a specific term for the following type of C code? In my example, I want to increase the depth of scope for a small chunk of code within a function without having to use needless if/else/for statements so that I can re-declare a variable with the same name multiple times. eg:
void myfunc(void) {
int a = 0, b = 1;
{
int c;
c = 3;
printf("c is: %d", c);
}
a = 2;
{
int c = 5;
printf("c is %d", c);
}
}
What is the term used to describe how I just wrapped some code in curly braces and increased the scope depth so the rest of the function doesn't see the 'c' int?
Thanks!
Scope is defined as the area in which the object is active. There are five scopes in C. They are as follows.
Program Scope
These are the declarations at the top most layers. They are available up to the life of a program. All the functions have this scope. This is otherwise known as global scope.
File Scope
It has scope such that it may be accessed from that point to the end of the file.
void dummy(void) { }
// absence of static automatically gives program scope to `dummy()`
static void dummy(void) { }
// static keyword here gives function `dummy()` a file scope
Function Scope
Only labels have this scope. In this scope, they are active up to end of the function.
void printFun()
{
print:
printf(“i is less than j”);
}
int main()
{
int i=1,j=2;
if(i < j)
goto print;
}
This code will be flagged error by the compiler saying that the label print is not known because labels have only function scope. If you have to jump unconditionally between the functions, you have to use setjmp/longjmp functions.
Block Scope
Declarations that are active up to the end of the block (where a block is defined as statements within { }). All the declarations inside the function have only block scope.
int fun(int a, int b)
{
int c;
{
int d;
}
// a, b, c, d all have block scope
}
As I have said, function scope applies only to labels. So should not be confused with block scope. The function arguments are treated as if they were declared at the beginning of the block with other variables (remember that the function body is also considered as a block within { }). So the function arguments have block scope (not function scope).
Local scope is general usage to refer the scope that is either function or block scope.
Prototype Scope
They are having the scope only inside the prototype declaration. This scope is interesting because the variable names are valid only in the declaration of prototype and does not conflict with other variable names. It exists for very little time and of less use and so goes unnoticed.
int add(int a, float b);
Here the variables a and b are said to have prototype scope.
Selecting Minimal Scope
When a name has to be resolved, that name is searched in the minimal scope, and if that is not available, it is searched at higher levels of scope. So, if a variable has to be declared, you have to select a minimal scope possible. If you can limit your scope, that increases the efficiency, readability and maintainability of your program. If you want a variable which is not useful outside a block, declare it inside the block and not in the outer ones. Similarly, if you want a variable whose value will be accessed only within the function but has to retain the value between the function calls, opt for static variable to a global one.
I'd say you are introducing a new local scope, or a nested scope, or a block.
This becomes seriously important in C++ when you take active advantage of this:
{
std::lock_guard<std::mutex> lk(my_mutex);
do_critical_stuff(); // might throw exception?
}
// the lock is released automagically!
But even in C it's good practice to only use variables locally where they're needed and not bleed them into unnecessarily wide scopes.
The term is the scope.
K&R2 defines the word scope as
A name also has a scope, which is the region of the program in which
it is known
Scope is the word that refers to the visibility of an identifier.