Home > front end >  Why can't a global variable be initialised from another global?
Why can't a global variable be initialised from another global?

Time:12-03

int a = 5;
int b = a; //error, a is not a constant expression 

int main(void)
{
  static int c = a; //error, a is not a constant expression
  int d = a; //okay, a don't have to be a constant expression
  return 0;
}
  1. I don't understand what happens when a C compiler handles those variable declarations.

  2. Why was C designed to be unable to handle int b = a?

CodePudding user response:

The specific rule that applies here is C 2018 6.7.9 4:

All the expressions in an initializer for an object that has static or thread storage duration shall be constant expressions or string literals.

The primary reason for this arises from the way that C is typically implemented, with a compiler generating object modules (which are later linked into executables and run). In such a C implementation, initializing an object with static storage duration requires the compiler to know the initial value, whereas initializing an object with automatic storage duration does not require the compiler to know the initial value.

This is because, to initialize an object with static storage duration, the compiler must put the initial value into the object module being generated. To initialize an object with automatic storage duration, the compiler merely needs to generate instructions to get or calculate the initial value and store it in the object.

When int a = 5; and int b = a; appear outside of any function, a and b have static storage duration. At this point, the compiler could, in theory, see that a was initialized with the value five, so it has that value when used in int b = a;. However, there are some issues with this:

  • It requires the compiler to maintain knowledge about objects it is not currently required to maintain.
  • It can only be done in certain circumstances, as when the initializer for b uses only objects that have been initialized earlier in the same translation unit. Extending the language to require the compiler to support this would require more complicated rules.
  • It requires extending the language semantics to specify what values objects have before the program is executed at all.

Another possibility would be that, to make initializations like int b = a; work, the compiler does it by generating instructions to be executed when the program starts, possibly immediately before main is called. This adds complications, including:

  • If int b = a; appears in a translation unit other than the one containing main, how is the code necessary to initialize b inserted in main or in the program start-up code?
  • When there are multiple such initializations, some of which may depend on each other, how do you ensure they are executed in the desired order?

These problems could be solved, in theory, but C is intended to be a “simple” language.

CodePudding user response:

This happens because variables declared outside any function (at file scope) or variables declared as static both get static storage duration. Such variables are initialized before main() is even called. And that early on in the execution, values that aren't pure constant expressions might not yet be available.

RAM-based hosted systems like PC might even initialize such variables in one go, at the point where the executable is copied from the hard-drive to RAM, which gives very fast initialization. Which wouldn't be possible if you did something like static x = func(); because then you definitely have to execute func() before setting x.

There's also the issue of static initialisation order. Suppose a and b were declared in separate files, which should get initialized first, a or b?

C unlike C has decided to allow more complex forms of initialization and as a result, C has very complex initialization rules. And also it is a very common C bug to write code depending on the order of static initialization. There are valid arguments for/against both the C and the C way.

  • Related