Discussion:
Order of initialization for multiple declarators in a single declaration
(too old to reply)
Andrey Tarasevich
2015-01-11 23:24:40 UTC
Permalink
Raw Message
Just looked through C99 and C11 trying to figure out whether they
guarantee that multiple declarators in a single declaration are executed
in declaration order, i.e. from left to right. The standard does say
that each full declarator ends in a sequence point

6.7.5 Declarators (C99)
6.7.6 Declarators (C11)

3 A full declarator is a declarator that is not part of another
declarator. The end of a full declarator is a sequence point.[...]

Yet there seems to be nothing that says that individual initializations
shall be carried out in left-to-right direction. Is it really
unspecified or am I missing something simple?

int main() {
int i = 0;
int a = i++, b = i++;
// Are values of `a` and `b` specified here?
}

If it is supposed to be unspecified, then what is the practical value of
the aforementioned sequence points at the end of each full declarator?
(I understand that it turns undefined behavior into unspecified behavior
in the above code sample, but in this case it has little or no practical
value.)
--
Best regards,
Andrey Tarasevich
Kaz Kylheku
2015-01-12 01:25:25 UTC
Permalink
Raw Message
Post by Andrey Tarasevich
int main() {
int i = 0;
int a = i++, b = i++;
// Are values of `a` and `b` specified here?
}
If it is supposed to be unspecified, then what is the practical value of
the aforementioned sequence points at the end of each full declarator?
(I understand that it turns undefined behavior into unspecified behavior
in the above code sample, but in this case it has little or no practical
value.)
The practical value of unspecified behavior over undefined in this
specific case (assuming this is all true) is that you either have
a == 0 && b == 1, or you have a == 1 && b == 0. There is no third
possibility of the proverbial demons flying out of your nose.

There are conceivable situations in which you might not care about
the order, even if the results are different. I can readily think of one. In
the C guts of my TXR programming language project, I could easily have code
like:

{
val a = gensym(), b = gensym();

/*...*/
}

Suppose that the gensym counter is at 24. I don't care about that.
All I care is that a and b are distinct symbols (compare unequal under
the strictest equality); I do not care which symbol gets the name "G0025" and
which one gets the name "G0026".

In the me_pprof function, there are four calls to gensym, that could
be combined into a single declaration, or scrambled into any of hte
16! possible orders, even though gensym has a global effect:

http://www.kylheku.com/cgit/txr/tree/eval.c?id=b265fb4a0140d4a65533ee95aea2d34966a34017#n2091
Andrey Tarasevich
2015-01-12 05:00:06 UTC
Permalink
Raw Message
Post by Kaz Kylheku
There are conceivable situations in which you might not care about
the order, even if the results are different. I can readily think of one. In
the C guts of my TXR programming language project, I could easily have code
{
val a = gensym(), b = gensym();
/*...*/
}
Suppose that the gensym counter is at 24. I don't care about that.
All I care is that a and b are distinct symbols (compare unequal under
the strictest equality); I do not care which symbol gets the name "G0025" and
which one gets the name "G0026".
Yes, I thought about that. But is case of a genuine function `gensym()`
the proper functionality is already ensured by the sequence points
present in the function call itself. The genuine need for a sequence
point would arise in case of a naked variable

int a = ++genint, b = ++genint;

But, again, if the initialization order is unspecified, I don't see any
fundamental difference between the above initialization in a declaration
and, say, function parameter initialization in a function call
expression. In case of function parameter initialization the order is
unspecified and there are no sequence points between the parameters.
Your `gensym()` still works as intended, but a naked variable doesn't
(undefined behavior). What makes initialization in a declaration so
different to require an extra sequence point?
--
Best regards,
Andrey Tarasevich
Kaz Kylheku
2015-01-12 06:19:53 UTC
Permalink
Raw Message
Post by Andrey Tarasevich
Post by Kaz Kylheku
There are conceivable situations in which you might not care about
the order, even if the results are different. I can readily think of one. In
the C guts of my TXR programming language project, I could easily have code
{
val a = gensym(), b = gensym();
/*...*/
}
Suppose that the gensym counter is at 24. I don't care about that.
All I care is that a and b are distinct symbols (compare unequal under
the strictest equality); I do not care which symbol gets the name "G0025" and
which one gets the name "G0026".
Yes, I thought about that. But is case of a genuine function `gensym()`
the proper functionality is already ensured by the sequence points
present in the function call itself.
By the way, deja vu, I would swear this topic came up recently. Either in this
newsgroup or comp.lang.c, something like within the last year, perhaps.
Andrey Tarasevich
2015-01-12 23:06:30 UTC
Permalink
Raw Message
Post by Andrey Tarasevich
If it is supposed to be unspecified, then what is the practical value of
the aforementioned sequence points at the end of each full declarator?
(I understand that it turns undefined behavior into unspecified behavior
in the above code sample, but in this case it has little or no practical
value.)
One of the consequences of it being unspecified is that the following
code is actually invalid

int array[N];
for (int *element = array, *element_end = element + N;
element != element_end;
++element)
*element = 0;

It can be fixed by initializing `element_end` with `array + N` instead
of `element + N`, but still... Another thing to keep in mind when
writing cross-compilable C-C++ code.
--
Best regards,
Andrey Tarasevich
Woong Jun
2015-01-13 00:17:15 UTC
Permalink
Raw Message
Post by Andrey Tarasevich
Just looked through C99 and C11 trying to figure out whether they
guarantee that multiple declarators in a single declaration are executed
in declaration order, i.e. from left to right. The standard does say
that each full declarator ends in a sequence point
6.7.5 Declarators (C99)
6.7.6 Declarators (C11)
3 A full declarator is a declarator that is not part of another
declarator. The end of a full declarator is a sequence point.[...]
Yet there seems to be nothing that says that individual initializations
shall be carried out in left-to-right direction. Is it really
unspecified or am I missing something simple?
Probably, N1548 6.8p3:

The initializers of objects that have automatic storage duration, and
[VLA stuff omitted], are evaluated and the values are stored in the
objects (...) each time the declaration is reached in the order of
execution, as if it were a statement, and within each declaration in
the order that declarators appear.


--
Jun, Woong (woong.jun at gmail.com)
Web: http://code.woong.org
Tim Rentsch
2015-01-13 00:19:47 UTC
Permalink
Raw Message
Post by Andrey Tarasevich
Just looked through C99 and C11 trying to figure out whether they
guarantee that multiple declarators in a single declaration are
executed in declaration order, i.e. from left to right. The
standard does say that each full declarator ends in a sequence
point
6.7.5 Declarators (C99)
6.7.6 Declarators (C11)
3 A full declarator is a declarator that is not part of another
declarator. The end of a full declarator is a sequence
point.[...]
Yet there seems to be nothing that says that individual
initializations shall be carried out in left-to-right direction.
Is it really unspecified or am I missing something simple?
What you are missing is 6.8 p3/p4. There is a key phrase in
paragraph 3:

..., and within each declaration in the order that
declarators appear.

The wording of paragraph 4 is slightly cleaned up in C11 relative
to C99, but the two paragraph 3's are identical.
Post by Andrey Tarasevich
int main() {
int i = 0;
int a = i++, b = i++;
// Are values of `a` and `b` specified here?
}
If it is supposed to be unspecified, [snip]
Taking into account the stipulations in 6.8, the behavior here
is well-defined, with 'a' getting 0 and 'b' getting 1. Within
a single declaration, initializers are evaluated in the order
they appear, with a sequence point after each one.
Andrey Tarasevich
2015-01-13 18:17:57 UTC
Permalink
Raw Message
Post by Tim Rentsch
Post by Andrey Tarasevich
Just looked through C99 and C11 trying to figure out whether they
guarantee that multiple declarators in a single declaration are
executed in declaration order, i.e. from left to right. The
standard does say that each full declarator ends in a sequence
point
6.7.5 Declarators (C99)
6.7.6 Declarators (C11)
3 A full declarator is a declarator that is not part of another
declarator. The end of a full declarator is a sequence
point.[...]
Yet there seems to be nothing that says that individual
initializations shall be carried out in left-to-right direction.
Is it really unspecified or am I missing something simple?
What you are missing is 6.8 p3/p4. There is a key phrase in
..., and within each declaration in the order that
declarators appear.
The wording of paragraph 4 is slightly cleaned up in C11 relative
to C99, but the two paragraph 3's are identical.
Right. Thank you. (And I thought that I combed the whole document for
every occurrence of the word "order"...)
--
Best regards,
Andrey Tarasevich
Loading...