When I initialize the array below all the output looks ok except for values[3]
. For some reason values[3]
initialized as values[0]+values[5]
is outputting a very large number. My guess is that I am trying to assign values[0]+values[5]
before they are properly stored in memory but if someone could explain that would be great.
int main (void)
{
int values[10] = {
[0]=197,[2]=-100,[5]=350,
[3]=values[0] + values[5],
[9]= values[5]/10
};
int index;
for (index=0; index<10; index++)
printf("values[%i] = %i\n", index, values[index]);
return 0;
}
The output is as follows:
values[0] = 197
values[1] = 0
values[2] = -100
values[3] = -1217411959
values[4] = 0
values[5] = 350
values[6] = 0
values[7] = 0
values[8] = 0
values[9] = 35
It looks like you are subject to unspecified behavior here, since the order of evaluation of the initialization list expressions is unspecified, from the draft C99 standard section
6.7.8
:and note 133 says:
As far as I can tell, the normative text that backs up note133
would be from section6.5
:and we can see that an intializer is a full-expression from
6.8
(emphasis mine):After looking back at one of my old C++ answers that covered sequence points within an initializer and which places the full-expression in a different place then I originally concluded, I realized the grammar in
6.7.8
contained initializer twice:I originally did not notice this and thought the statement on full-expressions applied to the top element in the above grammar.
I now believe like C++ the full-expression applies to each initializer within the initializer-list which make my previous analysis incorrect.
Defect report 439 confirmed my suspicion that this was indeed the case, it contains the following example:
and it says:
so each intializer within
INITIALIZERS
is a full-expression.Since this defect report is against C11 it is worth noting that C11 is more verbose then C99 in the normative text on this issue and it says:
There is undefined behavior in the case where the following expressions are evaluated before the respective elements in
values
are assigned to:or:
This is undefined behavior since using an indeterminate value invokes undefined behavior.
In this specific case the simplest work-around would be to perform the calculations by hand:
There are other alternatives such as doing the assignments to element
3
and9
after the initialization.edit:
The ISO C99 standard, section 6.7.8 (Initialization) specifies that
But as Shafik pointed out, the evaluation order doesnt have to match the initialization order
Which means
values[0] + values[5]
may read garbage values from:values[0]
values[5]
(this is what happen in your case)Try this code:
And then you print the array like you've done.
This is the first time that I have seen something initialized that way, but I figured that the behavior you are seeing had to do with accessing a piece of the array that has not yet been initialized. So I built it using GCC 4.6.3 on a 32-bit Ubuntu 12.04 system. In my environment, I got different results than you.
I've identified a key line in the above output that I think marks the difference between what yours generated and what mine generated (marked with <======). Before specific array elements are initialized with the values you specified, mine is zeroing the contents of the array. The specific initialization of array elements occurs after this.
Given the above behavior, I do not think that it is unreasonable to hypothesize that yours did not zero the array contents prior to initializing specific elements of the array. As to why the difference in behavior? I can only speculate; but my first guess is that we are using two different compiler versions.
Hope this helps.
This has nothing to do with designated initializers as such. It is the same bug as you'd get when attempting something like this:
The order in which initialization list expressions are executed is simply unspecified behavior. Meaning it is compiler-specific, undocumented and should never be relied upon:
C11 6.7.9/23
Since you are using array items to initialize other array members, it means that you must change your code to run-time assignment instead of initialization.
As a side-effect, your program will now also be far more readable.