Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interdependent initialization with commas?

Is the following perfectly defined:

int x = 42, y = x;

i.e. strictly equivalent to:

int x = 42;
int y = x;

EDIT : the question is not about style (I know that it's wrong...), the question is "theoretical"

like image 367
Vincent Avatar asked Jun 14 '14 20:06

Vincent


People also ask

How are commas used in the initialization and iteration parts of a for statement?

We separate each instances with a comma(,) . In this case, when the for loop is entered, both argc-- and argv++ expressions in the initialization part are executed. From then onward, every time the loop is iterated, both argc-- and argv++ expressions in the incremental part is executed.

What is the use of the comma operator in C?

The comma operator in c comes with the lowest precedence in the C language. The comma operator is basically a binary operator that initially operates the first available operand, discards the obtained result from it, evaluates the operands present after this, and then returns the result/value accordingly.


2 Answers

This question came up in comp.lang.c++.moderated a long time ago under the topic init-declarator-list analysis order and the conclusion there was Yes.

Although I see the full-expression argument but I do not see the order of evaluation argument. So I think this is unspecified.

The relevant part of the question is:

In this declaration and definition:

int a = 2, b = a;

Is it guaranteed that b will always be initialized as 2 ? If yes, then can we say that a = 2 is always analysed(or evaluated?) before b = a ?

and the relevant part of the answer is:

Yes. Strictly stated, the observable behavior of the program must be as if all of the side effects of the 'a = 2' part of the declaration took place before the evaluation of the 'b = a' part starts. (In practice, of course, in this simple example, a compiler could assign 2 to both a and b in any order, or even in parallel, because doing so would result in the same observable behavior.)

and further down:

In this particular case, however, it does separate the declarator list into separate declarators; each declarator contains a complete expression, and the declarators are evaluated in order.

Update

What makes each init-declator a full expression is subtle but as far as I can tell follows the same logic I used in Are multiple mutations of the same variable within initializer lists undefined behavior pre C++11. In this case we start from the grammar defined in ection 8:

init-declarator-list:
  init-declarator
  init-declarator-list , init-declarator
init-declarator:
  declarator initializeropt

The next point of focus is the initializer grammar which is covered in section 8.5:

initializer:
  brace-or-equal-initializer
  ( expression-list )
brace-or-equal-initializer:
  = initializer-clause
  braced-init-list
initializer-clause:
  assignment-expression
  braced-init-list

In both cases we have = initializer-clause which bring us to assignment-expression which if we follow the grammar in section 5 bring us back to primary-expression which can give us either a literal or id-expression.

So we do indeed have full-expressions separated by a grammatical comma so we have:

int x = 42, y = x;
          ^      ^
          |      end full-expression
          end full-expression

and according to section 1.9 paragraph 14 we see that:

Every value computation and side effect associated with a full-expression is sequenced before every value computation and side effect associated with the next full-expression to be evaluated.8.

As for the order of evaluation, I think this is not specified, the same logic that applies to defect report 430 for initializer lists would seem to apply here as well. In C++11 the language for initializer lists was fixed with the following addition in section 8.5.4:

Within the initializer-list of a braced-init-list, the initializer-clauses, including any that result from pack expansions (14.5.3), are evaluated in the order in which they appear. [...]

there is no such equivalent for initializer.

like image 195
Shafik Yaghmour Avatar answered Sep 21 '22 00:09

Shafik Yaghmour


The correct answer is that

int x = 42, y = x;

and

int x = 42;
int y = x;

are usually equivalent (not strictly).


Considering the standard § 8 Declarators [dcl.decl]:

3 Each init-declarator in a declaration is analyzed separately as if it was in a declaration by itself.

and in the footnote [100] further explains:

A declaration with several declarators is usually equivalent to the corresponding sequence of declarations each with a single declarator. That is

T D1, D2, ... Dn;

is usually equivalent to

T D1; T D2; ... T Dn;

where T is a decl-specifier-seq and each Di is an init-declarator.

  • The above guarantees that x = 42 and y = x will be evaluated separately. However, as @Praetorian correctly pointed out in the comments, footnotes are not normative.

  • This means that the order of evaluation is not well defined and an implementer could as well implement the evaluation of the declarations in the reverse order (i.e,. T Dn; ...T D2; T D1;).

  • One might argue that the comma operator is guaranteed left to right evaluation. However, this not the case. According to the K & R [K & R II, 3.6 p.63], that also applies to C++:

The commas that separate function arguments, variables in declarations, etc., are not comma operators, and do not guarantee left to right evaluation.

like image 45
101010 Avatar answered Sep 20 '22 00:09

101010