Duck Dodgers
Duck Dodgers

Reputation: 3461

Variables can only be "declared" globally, but cannot be modified/(initialized separately)

Disclaimer:

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
}
  1. 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?

  2. Any specific reason for this?

Upvotes: 3

Views: 965

Answers (3)

eerorika
eerorika

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

Lundin
Lundin

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.
  • Initialization of C++ objects with static storage duration, by their respective initializers.

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

dbush
dbush

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

Related Questions