Ray Hamel Ray Hamel - 3 months ago 14
C Question

Incrementing a variable used twice in an initializer list - undefined behavior?

Edit: Not already answered - the linked question was about ordinary r-values, initializer lists are a separate, if related concept.

Is this statement well-defined, or is using the prefix increment operator in an initializer list, on a variable that appears twice in the list, undefined behavior?

struct T t = { i, ++i };


I'm most interested in ANSI C, but it'd also be useful to know if other versions of C and/or C++ differ. And if similar constructs like the following are legal:

struct T t = { i, i++ };

struct T t = { ++i, ++i };

struct T t = { i++, ++i };

struct T t = { i++, i++ };

Answer

C

In C (not necessarily the same answer as for C++), there are no sequence points associated with the components of an initializer list.

The C11 standard, ISO/IEC 9899:2011, says in section §6.7.9 Initialization:

¶19 The initialization shall occur in initializer list order, each initializer provided for a particular subobject overriding any previously listed initializer for the same subobject; 151)

151) Any initializer for the subobject which is overridden and so not used to initialize that subobject might not be evaluated at all.

That sounds promising, but…

¶23 The evaluations of the initialization list expressions are indeterminately sequenced with respect to one another and thus the order in which any side effects occur is unspecified.152)

152) In particular, the evaluation order need not be the same as the order of subobject initialization.

So, (in C) the order of evaluation is indeterminately sequenced, and you cannot rely on when the increments occur (or, in extreme cases not illustrated by the code in the question, whether the increments occur).

In C99 (ISO/IEC 9899:1999), the section number is §6.7.8, but paragraphs 19 and 23 have essentially the same content, except that the footnote numbers are different.

In C90 (ISO/IEC 9899:1990), the issue is not addressed explicitly.

C++

Judging from songyuanyao's answer, the rules in C++11 (and later) are different from those in C11. This sort of thing emphasizes that the languages C and C++ are different and makes writing comprehensive answers to questions tagged with both languages extremely difficult.

Closely related questions

There are at least two other questions related to side-effects (such as ++) in contexts other than initializers. They both should be read too. The second, in particular, is of interest to C++ users; the first is tagged C and not C++ and so is of most relevance to those interested in C.

Both were pointed out by πάντα ῥεῖ in the comments.