Reputation: 3461
Disclaimer:
C/C++
double tag, because I tested the bit of code on both C and C++ and it is just 4 lines of code (and the only difference is that gcc/clang
give a warning while g++/clang++
give an error.)Background:
In replying to another question, I started to think about why the OP can not modify a public static
variable. I thought about it a bit and then reduced the problem a bit further, where I can see the same effect, but without needing any class or static member variables.
Question: Then the following code can reproduce the observation.
int global_n; // I know it can be initialized right away here also: int global_n = 1;
global_n = 2; // This does not compile in C++. In C it gives a warning about missing type-specifier
int main() {
global_n = 2; // This does compile in both C/C++ of course
}
Which brings me to my question: Global variables (and hence static
variables/member-variables) can only be initialized, directly there when they are declared. But any subsequent modifications can only occur inside a function. Correct?
Any specific reason for this?
Upvotes: 3
Views: 965
Reputation: 238351
My answer is regarding C++. C may be different.
Global variables (and hence static variables/member-variables) can only be initialized, directly there when they are declared.
True, it is only possible to provide an initialiser in a declaration. It is however possible to provide declarations without an initialiser. Example:
extern int global_n; // only declaration; no definition; no initialiser
int global_n = 42; // re-declaration; definition; initialiser
But any subsequent modifications can only occur inside a function. Correct?
Not strictly true. It is possible to modify global variables in an initialiser of another global variable:
int global_n1 = 666;
int global_n2 = global_n1 = 42;
This is probably a bad design choice in practice - at least in this simplified example; I suppose there can be practical use case out there.
Any specific reason for this?
I presume you mean, any specific reason why you can only have declaration statements, and no other kind of statement outside of functions?
That's simply a design choice of the language. C++ programs are separate units linked together. In what order should the statements be executed when they come from separate source files? How about their execution in relation to initialisation of static objects? The current state of static initialisation is complicated enough; I think it was a good choice to not allow expression statements in namespace scope.
Upvotes: 1
Reputation: 213862
The simple answer is that the syntax doesn't allow to execute code outside of compound statements {...}
, end of story.
But if digging a bit deeper, C also does not allow things like
// file scope
int x = 0;
int y = x;
Nor does C allow this:
// file scope
int x = func();
The reason for this is that file scope variables, and variables declared as static
all have static storage duration. Such variables are actually not initialized on the line where you declarate them, but much earlier on, before main() is even called. (This goes for C++ objects with static storage duration too.)
There is always start-up code executed before main() is called, even if you don't see it. This is often called "C runtime" or "CRT". Part of it's job is to initialize all variables/objects with static storage duration before main() is called.
So if you have this application code:
void foo (void)
{
static int var = 1;
printf("%d", var);
}
int main (void)
{
foo();
}
Then the code executed before main
will look something like this simplified pseudo code:
void startup (void) // point of entry when executable starts
{
set memory of "var" to 1
main();
}
This is actually the reason why we can call foo
multiple times without re-initializing var
. The line static int var = 1;
isn't actually executed where it is placed in the source, but much earlier on, and only once. Unlike local variables, that are often initialized at the same place in the code as the declaration.
The "CRT" initialization is roughly split in three parts:
.data
initialization which sets all static storage duration variables that are explicitly initialized to a value by the programmer, like var
in my example..bss
initialization which sets all variables to zero, that are either initialized to zero by the programmer, or not initialized at all.Apart from such C++ constructs, no application code is called at start-up, which is why code like int x = func();
isn't allowed in C.
This is also the reason why C++ objects with static storage duration shouldn't be made to rely on each other's initialization values: the order of declaration in the source doesn't necessarily correspond with the order of initialization in the "CRT".
Upvotes: 2
Reputation: 223972
Outside of a function, you cannot have statements (i.e. executable lines of code), only declarations and definitions.
In the case of global_n = 2;
at global scope, C90 has a legacy feature that if a variable is declared without a type then the has a default type of int
(C99 removed the feature and requires a type). That's what's happening in this case, and that's also why you get a warning about the type missing.
C++ doesn't have that rule, so this appears as a statement outside of a function which is an error.
Upvotes: 4