In the following code, are the variables x,y,z initialized during run time when memory is allocated to them or at compile time ?
int main(void)
{
int x = 5;
static int y=5;
int z[] ={1,2,3,4};
return 0;
}
In the following code, are the variables x,y,z initialized during run time when memory is allocated to them or at compile time ?
int main(void)
{
int x = 5;
static int y=5;
int z[] ={1,2,3,4};
return 0;
}
As the comments have stated, it is not defined whether variables are initialised at runtime, even with the information you gave in comments that they are inside the scope of a function. Only the behaviour is like a virtual machine doing initialisation one time or another.
It is however possible to be sure that they are not initialised at compile time.
Specified by standard or not, there is no way any real machine could do that.
(I will happily edit my answer and remove this statement if anybody comes up with an example of how this would be possible. Software emulators and anything not based on a compiler, like a C-interpreter, do not count.)
At compile time, only the value can be determined with which these variables will be initialised. For the cases in your example that value determination does happen, because the value is not available from anywhere else but the digits in program text.
The initialisation (i.e. the "arrrival" of those values in the memory piece represented by the identifiers) can happen at different times, but never at compile time. Because at compile time no such memory piece has been selected yet. In case of cross-compilation it might not even exist yet (the chip to run it on not having been produced yet).
The following initialisation times are possible
(not saying "usually done" for all of them...):
For your examples, inside scope of main()
, either of those options might apply.
So again, it is not known.
Notes:
I make a difference between load time and memory setup time here, because memory setup time is usually associated with power-on or reset situations, which are somewhat exceptional, while loading a program to execute is perceived as a normal situation.
Both could however be considered the same thing from point of view of the C-program being executed, as being "before main()
".
I also make a difference between runtime (as being controlled by the program as defined by C-code you wrote) and load/setup time, which are part of the C runtime environment preparation code. C-runtime might be prepared via OS or (e.g. for embedded environments) via machine code (not based on C) linked from reset vector.
The question does not have a clear answer. Initialization is something that happens in the abstract machine the C standard uses to describe how a program must behave, and the only requirements in implementing that machine are that the observable behavior described by the standard must be produced. The initial value of an object may be produced at compile time (even if calculating that initial value requires a complex calculation) or at run time (even if the initial value is a simple constant) or not at all (as long as the observable behavior of the program is produced in some way). Furthermore, the initial value might appear in immediate values encoded into instructions, in memory described by the object file, in memory when written during program start-up, in memory when written while executing a function, in a register, or elsewhere. An object might be held in different places at different times, and it might share storage with other objects or with other instances of itself (as when a function executes recursively), even simultaneously.
A more useful question to ask is: What are the costs and effects of various object initializations? Again, this is not defined by the C standard, but it has real-world consequences. Initialization of many objects or large objects can have a noticeable drag on performance and can affect product quality.
The rest of this answer assumes one is using a compiler of good quality and is requesting optimization (as with the -O3
or -Os
switch using Clang or GCC).
A declaration such as int x = 5
at block scope is likely to result in 5 being hard-coded into an instruction, if it is needed at all. The initial value might not be needed because the compiler optimizes further work with x
so that the initial value is incorporated into the first expression(s) that use x
. (In the code shown in the question, x
is not needed at all since it is never used, so the compiler will remove it from the program entirely.)
A declaration such as static int y = 5
is likely to result in 5 being written into a data section in the object file (and, when the object file is linked to make an executable file, the data section will be copied or merged into the executable file). Again, this can be subject to optimization.
If int x = 5
were declared at file scope, it is an external definition, and the compiler must make it available to other translation units (compilations of other source files), so it has to be stored in memory (unless the compiler and other developer tools are capable of optimization across translation units). In this case, the compiler is likely to write 5 into a data section of the object file.
With small objects and simple initial values such as these, there is almost never any reason to be concerned with when or how they are initialized, because the costs are so cheap and because no improvements are available.
With int z[] = { 1, 2, 3, 4 };
at block scope, the array is small enough that the compiler might handle it in the same way as the single int x
above, depending on circumstances. In the situation where the array is larger, this situation might be handled:
The values 1, 2, 3, and 4 are written to a constant data section in the object file.
When execution effectively reaches the declaration, the compiler allocates storage for z
, likely on the stack, and copies the data from the constant data section into z
. (It may be hard to say when execution reaches the declaration, since the abstract machine model means the C implementation is free to rearrange many things. Execution of statements before and after the declaration may be rearranged and mixed together.)
However, suppose you have code like this:
int z[] = { 1, 2, 3, 4 };
for (int i = 0; i < 4; ++i)
z[i] = f(z[i]);
In this case, the compiler can see that no member of z
is changed before its initial value is passed to f
. When implementing this, the compiler might skip the step above of copying 1, 2, 3, and 4 into the storage allocated for z
. Instead, it may implement the loop by reading from the constant data, passing each value to f
, and writing the result to the storage allocated for z
. In this case, was z
ever initialized? The program had the initial values stored in the constant data section, but it never wrote them to the storage particularly allocated for z
. It only wrote derived values later on.
However, again, the real question is what are the costs of this? We had to store data in the constant data section, and we had to call f
repeatedly. Suppose z
had thousands of elements instead of four. Could we reduce those costs?
If f
is a pure function (depends only on its arguments, not any global state), then there is no point in storing 1, 2, 3, and 4. We ought to store f(1)
, f(2)
, f(3)
, and f(4)
and skip the execution of f
at run-time. If you have a good compiler and the source code of f
is visible while the compiler is compiling this code, the compiler might do that—it might store the results of calling f
rather than just the explicit initial values. (Even if f
is not visible, the compiler might do this for known functions, such as cos
or log
.)
If you are working on a project for which this is important, you should get to know your compiler and how well it does with things like this. There is no uniform answer, particularly as technology continues to develop.
If an initialization like this is important for your application, an alternative is to write a program that computes the initial values (f(1)
, f(2)
, and so on) and writes those into a new source file. At compile time, you would execute that program and then compile the resulting source code.
In C, initialization costs are not often a problem except when you have a lot of data that can be preprocessed with an auxiliary program as described above. It is more of a problem in C++ where constructors for classes can be quite extensive.
The compiler's job is to do what it's told. You have issued it with the program
int main(void)
{
int x = 5;
static int y=5;
int z[] ={1,2,3,4};
return 0;
}
The C standard permits a compiler to produce compiled code that replicates exactly the observable behaviour of your program.
To that end, any decent C compiler with optimisations turned up to maximum will produce compiled code that is equivalent to
int main()
{
}
If you want to know how your specific compiler has dealt with your source code, then check the generated output.