How Are Local and Global Variables Initialized by Default

Why are global and static variables initialized to their default values?

  1. Security: leaving memory alone would leak information from other processes or the kernel.

  2. Efficiency: the values are useless until initialized to something, and it's more efficient to zero them in a block with unrolled loops. The OS can even zero freelist pages when the system is otherwise idle, rather than when some client or user is waiting for the program to start.

  3. Reproducibility: leaving the values alone would make program behavior non-repeatable, making bugs really hard to find.

  4. Elegance: it's cleaner if programs can start from 0 without having to clutter the code with default initializers.

One might then wonder why the auto storage class does start as garbage. The answer is two-fold:

  1. It doesn't, in a sense. The very first stack frame page at each level (i.e., every new page added to the stack) does receive zero values. The "garbage", or "uninitialized" values that subsequent function instances at the same stack level see are really the previous values left by other method instances of your own program and its library.

  2. There might be a quadratic (or whatever) runtime performance penalty associated with initializing auto (function locals) to anything. A function might not use any or all of a large array, say, on any given call, and it could be invoked thousands or millions of times. The initialization of statics and globals, OTOH, only needs to happen once.

Are global variables always initialized to zero in C?

Yes, all members of a are guaranteed to be initialised to 0.

From section 3.5.7 of the C89 standard

If an object that has static storage duration is not initialized
explicitly, it is initialized implicitly as if every member that has
arithmetic type were assigned 0 and every member that has pointer type
were assigned a null pointer constant.

Are delphi variables initialized with a value by default?

Yes, this is the documented behaviour:

  • Object fields are always initialized to 0, 0.0, '', False, nil or whatever applies.

  • Global variables are always initialized to 0 etc as well;

  • Local reference-counted* variables are always initialized to nil or '';

  • Local non reference-counted* variables are uninitialized so you have to assign a value before you can use them.

I remember that Barry Kelly somewhere wrote a definition for "reference-counted", but cannot find it any more, so this should do in the meantime:

reference-counted == that are reference-counted themselves, or
directly or indirectly contain fields (for records) or elements (for
arrays) that are reference-counted like: string, variant, interface
or dynamic array or static array containing such types.

Notes:

  • record itself is not enough to become reference-counted
  • I have not tried this with generics yet

When does initialisation of global variables happen?

Since you didn't define the language you're talking about, I assumed it to be C++.

In computer programming, a global variable is a variable that is accessible in every scope (unless shadowed). Interaction mechanisms with global variables are called global environment (see also global state) mechanisms. The global environment paradigm is contrasted with the local environment paradigm, where all variables are local with no shared memory (and therefore all interactions can be reconducted to message passing). Wikipedia.


In principle, a variable defined outside any function (that is, global, namespace, and class static variables) is initialized before main() is invoked. Such nonlocal variables in a translation unit are initialized in their declaration order (§10.4.9). If such a variable has no explicit initializer, it is by default initialized to the default for its type (§10.4.2). The default initializer value for built-in types and enumerations is 0. [...] There is no guaranteed order of initialization of global variables in different translation units. Consequently, it is unwise to create order dependencies between initializers of global variables in different compilation units. In addition, it is not possible to catch an exception thrown by the initializer of a global variable (§14.7). It is generally best to minimize the use of global variables and in particular to limit the use of global variables requiring complicated initialization. See.

When are static and global variables initialized?

By static and global objects, I presume you mean objects with
static lifetime defined at namespace scope. When such objects
are defined with local scope, the rules are slightly different.

Formally, C++ initializes such variables in three phases:
1. Zero initialization
2. Static initialization
3. Dynamic initialization
The language also distinguishes between variables which require
dynamic initialization, and those which require static
initialization: all static objects (objects with static
lifetime) are first zero initialized, then objects with static
initialization are initialized, and then dynamic initialization
occurs.

As a simple first approximation, dynamic initialization means
that some code must be executed; typically, static
initialization doesn't. Thus:

extern int f();

int g1 = 42; // static initialization
int g2 = f(); // dynamic initialization

Another approximization would be that static initialization is
what C supports (for variables with static lifetime), dynamic
everything else.

How the compiler does this depends, of course, on the
initialization, but on disk based systems, where the executable
is loaded into memory from disk, the values for static
initialization are part of the image on disk, and loaded
directly by the system from the disk. On a classical Unix
system, global variables would be divided into three "segments":


text:


The code, loaded into a write protected area. Static
variables with `const` types would also be placed here.

data:


Static variables with static initializers.

bss:


Static variables with no-initializer (C and C++) or with dynamic
initialization (C++). The executable contains no image for this
segment, and the system simply sets it all to `0` before
starting your code.

I suspect that a lot of modern systems still use something
similar.

EDIT:

One additional remark: the above refers to C++03. For existing
programs, C++11 probably doesn't change anything, but it does
add constexpr (which means that some user defined functions
can still be static initialization) and thread local variables,
which opens up a whole new can of worms.



Related Topics



Leave a reply



Submit