Redeclaration of global variables allowed in C? - c

Why is this code allowed in C?
int x;
int main() {
printf("%d\n", x);
return 0;
}
int x = 2;
It compiles without warnings using -Wall -std=c89 with both gcc and clang.
I have previously thought that int x at global scope is equivalent to int x = 0. I find myself surprised.

int x;, at file scope, is a tentative definition as well answered by #PSkocik and will act like int x = 0; if a definition with initialization does not exist.
I have previously thought that int x at global scope is equivalent to int x = 0.
The tricky part about a "global" int x; is assuming it is initialized with 0. It is initialized with 0 if another int x = constant; does not exist in any compilation unit.
Therefore recommend explicit initialization and not counting on default initialization to 0 bits when the object needs initialization.
// Does an initialization exist, in some file -maybe?
int x;
// Better. If another file initializes `x`, good to see a compiler/linker error.
int x = 0;

int x;
Is a declaration.
int x = 2;
Is a definition (which is also a declaration).
Re-declaration is allowed as long as the declarations are compatible (the same).
int x;
int x;
Will work. Re-definition is not allowed
int x = 2;
int x = 2;
Will not work.
Use without a declaration before it or without a definition is disallowed

Related

How to properly define external variables?

In the program
case0.c
int main()
{
int x;
x = 4;
}
x is first declared as an int, and memory is allocated for x on the following line. No problems here.
However, if I write the files (as part of a bigger program)
case1.c
extern int x;
x = 4;
I get, from gcc, warning: data definition has no type or storage class. Similarly, if I do
case2.c
extern int x = 4;
gcc also doesn't like it and gives warning: 'x' initialized and declared 'extern'
The only case that doesn't throw any warnings is
case3.c
extern int x;
int x = 4;
Why does case 1 give an error, when case 0 doesn't? Is case 3 the one and only way I should define external variables?
x is first declared as an int, and memory is allocated for x on the following line. No problems here.
No, that is not what happens. Inside a function, int x; defines x, which reserves memory for it. Then x = 4; stores a value in that memory.
extern int x;
x = 4;
extern int x; declares there to be an x but does not define it. If the program uses this x, it should define it somewhere else.
Outside a function, only declarations should appear. However, x = 4; is a statement, so it is not proper outside a function.
extern int x = 4;
This is valid C, but it is unconventional usage, so the compiler warns you. Conventionally, we write int x = 4; to define and initialize x, and we write extern int x; to declare x without defining it.
extern int x = 4; is defined by the standard; in this context, it is effectively the same as int x = 4;. But programmers generally do not use that form.
(If there is a visible prior declaration of x, such as static int x;, then extern int x = 4; does differ from int x = 4;. extern int x = 4; will refer to the x of the prior declaration, whereas int x = 4; will attempt to create a new x.)
extern int x;
int x = 4;
extern int x; declares x but does not define it.
int x = 4; defines x and initializes it.
Is case 3 the one and only way I should define external variables?
If you only need to use x in one translation unit, you can use int x = 4; by itself, without extern int x;. If you need to use x in multiple translation units, you should put extern int x; in a header file and include that header file in each source file that uses x, including the one that defines it.
"Is case 3 the one and only way I should define external variables?"
No, not if it is to be visible and usable by other source files in the project. If it is only to be used in the file in which it is created, there is no reason to give it extern duration.
The scenario requiring a variable with extern duration is when the value it stores is required to be referenced by multiple source files.
A common way (place) to create extern variables to support that scenario :
Declare variable with extern modifier in a header file.
Define the extern variable in a project file with visibility to its declaration. (eg, can be either a .h or .c . More commonly done in .c) If defined in a file other than the declaration file, file must #include the declaration file.
Use the extern variable in any source file by # including its declaration file
Example:
file.h
//anywhere in header file
extern int g_number;//declare extern variable.
//Note extern keywork required only during declaration
//Not during definition
//prototypes
void output_extern_variable( void );
void update_extern_variable( void );
...
file.c
//in file global space
#include "file.h"
int g_number = 25;//define extern variable
int main(void)
{
output_extern_variable();
update_extern_variable();
output_extern_variable();
...
file2.c
#include "file.h"
...
void output_extern_variable(void)
{
printf("Value of g_number is: %d\n", g_number);
}
void update_extern_variable( int *var )
(
g_number += 1;
)

How do you disambiguate a local static variable and a global variable that have the same name

below is my code:
//main.c
int x = 9;
int f()
{
static int x = 0;
x += 1;
return x;
}
int main()
{
printf("Value is %d", f());
return 0;
}
my questions are:
Q1-inside f(), there is a local static varaible x defined, and there is gloabal variable also called x, the program does compile, but isn't it a conflict to the compiler and linker?
Q2-when I run it, the output is 1, which means that the x in x += 1; is the local static varaible x, not the gloabal variable x.But I could have mean "increment the global variable x", how can I do it?
A program can have the same name for local and global variables but the value of a local variable inside a function will take preference. There is no provision in C language to explicitly modify global variable with the same name as local inside local scope. In C++ though for accessing the global variable with same name, you'll have to use the scope resolution operator
#include <iostream>
using namespace std;
// Global variable declaration:
int g = 20;
int f()
{
int g = 0;
::g += 5;
return g;
}
int main () {
// Local variable declaration:
int g = 10;
cout << f(); // Local
cout << ::g; // Global
return 0;
}
Produces
0
25
Edit -
There is indeed a way to explicitly change the global scope variable inside local scope having same variable name ( only if global variable is not declared static )
int x = 9;
int f()
{
static int x = 0;
{
extern int x;
x += 1;
}
return x;
}
int main()
{
printf("Value is %d", f());
return 0;
}
Produces 0
Q1-inside f(), there is a local static varaible x defined, and there is gloabal variable also called x, isn't it a conflict to the compiler and linker?
No, the function always treats the local variable name first. The local name x in function f shadows the global name x.
Q2-when I run it, the output is 1, which means that the x in x += 1; is the local static varaible x, not the gloabal variable x.But I could have mean "increment the global variable x", how can I do it?
It's the same as your first question. You call f() which uses the local variable name x, which shadows the global name x. If you want the global x, you need to use it directly, not via function f.
Once conceptually, program control reaches the local declaration of x in f, the global x is shadowed. No syntax exists in C for accessing the global x.
Other than renaming one of the variables,
int f()
{
int* y = &x; // still refers to the global x
static int x = 0;
x += 1;
*y += 1; // increments the global x via the pointer
return x;
}
is an option, although not particularly sensible.
Q1. The language was intentionally designed this way so that we don't have to worry about what identifiers that reside in the global namespace - there can be quite a lot of them in large projects.
Internally the compiler doesn't use variable names at all, but sometimes their names must preserved for the purpose of generating debugger files (like ELF etc). In such situations, the compiler uses something called "name mangling" to keep the two variables separate internally. For example if I disassemble your code with gcc x86 and no optimizations, it names the local one x.0 internally, where the .0 thing is a compiler-specific addition, not to be confused with valid C syntax.
Q2. From inside the function f where the local x is visible, you can't. Unless you explicitly pass along a pointer to the other variable through a parameter etc. Again, we wouldn't want to change file scope variable values by accident.
Q1 -inside f(), there is a local static variable x defined, and there is global variable also called x, the program does compile, but isn't it a conflict to the compiler and linker?
No, it is not a conflict. What is going on here is the proce variable shadowing. The local x shadows the global x.
Q2 - when I run it, the output is 1, which means that the x in x += 1; is the local static variable x, not the global variable x. But I could have mean "increment the global variable x", how can I do it?
Declare the global variable new with extern inside an inner scope and return from that scope:
int f (void)
{
static int x = 0;
{
extern x;
x += 1;
return x;
}
}
Note that this won't work if the global x would be declared as static without adding code at the global space.

Do cycles have their own stack record? (aka why is this code legal)

Ok, so I'm having a little question for you here.
I'm going to write code in C, but I guess this would work just the same in most languages.
So, why is this code legal:
int x = 1;
while(true) {
int x = x + 2;
}
While this calls for error: redefinition of ‘x’
int x = 1;
int x = 3;
So, I am aware that I'd be able to use the same name for a variabile in different functions within my program, since each function call would have its own stack record.
But do cycles have their own stack records as well? On a memory level, code #1 doesn't result in me having N different associactions for the variable x within the same stack record block?
In short, why in code #2 I'm redefining the x variable, but in code #1 I am not?
The two variables are declared in different scope.
int x = 1;
while(true) {
int x = x + 2;
}
The variable declared in the inner scope hides the variable declared in the outer scope.
Pay attention to that this declaration
int x = x + 2;
has undefined behavior because the declared variable is used itself as an initializer though it was not initialized.
For example you can write
int x = 1;
int main( void )
{
int x = 2;
while ( 1 )
{
int x = 3;
/*...*/
}
}
In this program there are declared and defined three different objects with the name x.
The first variable has the file scope while the other two have block scopes.
As for this code snippet
int x = 1;
int x = 3;
two variables in the same scope are defined with the same name.
In C (but not in C++) you may write
#include <stdio.h>
int x;
int x = 1;
int main(void)
{
return 0;
}
because in the file scope this
int x;
is not a definition of the variable x but is only its declaration.
Also you may write for example
#include <stdio.h>
int x;
int x = 1;
int main(void)
{
extern int x;
printf( "x = %d\n", x );
return 0;
}
The line
extern int x;
introduces the declaration of the global variable x in the block scope of main.
As for the while statement then (The C STandard, 6.8.5 Iteration statements
)
5 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.

Global variable does not take new value

I was making a simple C program
#include<stdio.h>
static int a;
a = 5;
int main()
{
printf("%d",a);
return 0;
}
Compiler error: "non static declaration of 'a' follows static declaration"
What does this error mean?
what this error log means?
It is a little tricky: what looks like an assignment
a = 5;
is treated as
int a = 5;
due to an old C rule that allowed you to declare int variables and int-returning functions without specifying their type explicitly (this is definitely not a good idea in the modern version of C).
Note that this is treated as a declaration with an implicit int only in the scope outside a function body.
You can fix it by combining the declaration with initialization, like this:
static int a = 5;
Outside a function you can only declare variables, you cannot have actual code statements.
a = 5;
is being interpreted as another declaration, when your intent I think is to write some code.
instead declare and initialise a at the same time
static int a = 5;
Your first declaration of a is static (ahas internal linkage).
The second declaration is not static (a has external linkage). Yes, a = 5; is a declaration with implicit type int in this case.
Both do not agree.
Btw. for functions this would be o.k. because the second declaration would "inherit" the internal linkage.
We cannot write any assignment statement globally. For example:
#include <stdio.h>
static int i=10; //Initialization statement
i=25; //Assignment statement
int main(){
printf("%d",i);
return 0;
}
Output: Compilation error
Note: Assigning any value to the variable at the time of declaration is known as initialization while assigning any value to variable not at the time of declaration is known assignment.
You can't set value as you did it: a = 5; before main(...). See code below:
static int a = 1; //default = 0;
int main()
{
printf("a = %d\n", a);
a = 2;
printf("a = %d\n", a);
return 0;
}
Output:
a = 1
a = 2
A = 5 is considered as an attempt to create another variable called a. You should put the = 5 after static int a.
Static int a = 5;
Just a little modification to your code will help you to understand it.
#include<stdio.h>
//static int a; //comment this statement
a = 5;
int main()
{
printf("%d",a);
return 0;
}
now compile this code [please enable your compiler's warnings]
Then you will get a warning something like this
data definition has no type or storage class [enabled by default]
So now try to understand this warning it means that compiler treat statement a=5 as a definition but without data type. But compiler unable default data type that is int.
so this statement is equivalent to
int a=5;

how to use extern in C?

I have this code:
#include <stdio.h>
extern int x;
void a() {
int x = 100;
printf("%d ",x );
x += 5;
}
void b() {
static int x = -10;
printf("%d ", x);
x += 5;
}
void c(){
printf("%d ", x);
x += 2;
}
int main() {
int x = 10;
a();
b();
c();
a();
b();
c();
printf("%d ", x);
getchar();
return 0;
}
int x = 0;
I was sure that the fact that extern in declared here, I will have a compilation error - but everything passed.
also , what is the meaning of extern when it's inside the C file itself? shouldn't it be in another file?
Is there a way to declare this variable in order for this not to compile?
The extern keyword declares a variable, and tells the compiler there is a definition for it elsewhere. In the case of the posted code, the definition of x occurs after main(). If you remove the int x = 0; after main() the code will not build (it will compile but will fail to link due to undefined symbol x).
extern is commonly used to declare variables (or functions) in header files and have the definition in a separate source (.c) file to make the same variable available to multiple translation units (and avoid multiple definition errors):
/* my.h */
#ifndef MY_HEADER
#define MY_HEADER
extern int x;
#endif
/* my.c */
#include "my.h"
int x = 0;
Note that the declaration of x in functions a(), b() and main() hide the global variable x.
You have a declaration for an identifier at file scope, so if no other declaration for the identifier would've been existing at file scope, the identifier would have had and external linkage. But, you've defined the identifier at file scope at the last line, in the pasted code.
So,extern int x;
refers to the globally defined: int x = 0; at the bottom of your file. :)
If you run this code you should get x's value as 2 and subsequently 4 because the externed x variable refers to the int x=0 after the main().
Extern is used for declaration a variable in a compilation unit, this variable was defined in other compilation unit.
What is the difference between a definition and a declaration?
For functions it is optional.
Read: http://en.wikipedia.org/wiki/External_variable
In your piece of code, each of the three function uses another 'i'. Only c() uses the global x.

Resources