Possible Duplicate:
array initialization, is referencing a previous element ok?
I wonder if its safe to do such initialization in c/c++ standard:
int a = 5;
int tab[] = { a , tab[0] + 1 , tab[1] };
It successfully compiles and executes with gcc 4.5 and clang 2.9, but will it always be true?
Printing this table gives 5 6 6
. Its initialized in global scope.
Generally its interesting in both, c and c++, but i want to use it in c++:)
Initializer List: To initialize an array in C with the same value, the naive way is to provide an initializer list. We use this with small arrays. int num[5] = {1, 1, 1, 1, 1}; This will initialize the num array with value 1 at all index.
No. The array is not being created twice. It is being created once and then it is being populated.
Initialize Arrays in C/C++ c. The array will be initialized to 0 if we provide the empty initializer list or just specify 0 in the initializer list.
C++03/C++11 answer
No, it won't.
On the right-hand side of the =
, tab
exists1 but — if it has automatic storage duration — it has not yet been initialised so your use of tab[0]
and tab[1]
is using an uninitialised variable.
If tab
is at namespace scope (and thus has static storage duration and has been zero-initialized), then this is "safe" but your use of tab[0]
there is not going to give you 5
.
It's difficult to provide standard references for this, other than to say that there is nothing in 8.5 "Initializers"
that explicitly makes this possible, and rules elsewhere fill in the rest.
1
[n3290: 3.3.2/1]:
The point of declaration for a name is immediately after its complete declarator (Clause 8) and before its initializer (if any) [..]
int a =5;
int tab[] = { a , tab[0] + 1 , tab[1] };
If these variables are declared at namespace scope, then they're okay, as at namespace scope variables are zero-initialized (because of static initialization - read this for detail).
But if they're declared at function scope, then second line invokes undefined behaviour, since the local variables are not statically initialized, that means, tab[0]
and tab[1]
are uninitialized, which you use to initialize the array. Reading uninitialized variables invokes undefined behavior.
In the C99 standard, it seems that the order of initialization of the members is guaranteed:
§6.7.8/17: Each brace-enclosed initializer list has an associated current object. When no designations are present, subobjects of the current object are initialized in order according to the type of the current object: array elements in increasing subscript order, structure members in declaration order, and the first named member of a union. In contrast, a designation causes the following initializer to begin initialization of the subobject described by the designator. Initialization then continues forward in order, beginning with the next subobject after that described by the designator.
But as @Tomalak mentions in the comment, that does not provide a full guarantee for the operation, as the compiler would first evaluate all of the arguments and then apply the results in the previous order. That is, the previous quote does not impose an order between the initialization of tab[0]
and the evaluation of the expression tab[0]+1
that is used to initialize tab[1]
(it only imposes an ordering between the initialization of tab[0]
and tab[1]
)
As of the C++ standard, neither in the current standard nor the FDIS of the upcoming C++0x standard seem to have an specific clause defining the order in which the initialization is performed. The only mention of ordering comes from
§8.5.1/2 When an aggregate is initialized the initializer can contain an initializer-clause consisting of a brace-enclosed, comma-separated list of initializer-clauses for the members of the aggregate, written in increasing subscript or member order.
But that only relates to the order by which the entries in the initializer are written, not how it is actually evaluated.
so, now I've run a couple of tests regarding your problem.
All compilations have been performed with your example code above, using the following scheme:
$(GCC) -o a.out test.c -Wall -Wextra -pedantic -std=$(STD)
This yielded the following results:
for GCC = gcc
, the standards -std=c89; -std=iso9899:1990; -std=iso9899:199409; -std=gnu89
resulted in a warning showing up: initializer element is not computable at load time
and undefined behaviour at runtime, meaning that the second and third value of the array were random garbage.
the standards -std=c99; std=iso9899:1999; -std=gnu99
did not produce this warning, but also showed undefined behaviour at runtime.
for GCC = g++
, the standards -std=c++98; -std=gnu++98; -std=c++0x
produced no warning, and the code worked as you'd expected it to, resulting in an array containing the values {5, 6, 6}
.
However, as most of the people advised, it might be unwise to use this, since your code might behave differently on other compilers, or maybe even other versions of the same compiler, which is generally a bad thing :)
hope that helped.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With