Discussion:
c initialization algorithm
(too old to reply)
Thiago Adams
2024-10-13 21:35:03 UTC
Permalink
The algorithm for C initialization as described in the standard and
implemented in gcc allow this.

struct X{
int a,b,c;
};

int main()
{
struct X x = {.a=1,2,3,.a=1, 2, 3};
}

https://godbolt.org/z/7naedbEM6

Basically, when a designed initializer is found the "cursor" goes to
that member and the following members are initialized in order.

struct X{
int a,b,c;
};

int main()
{
struct X x = {.a=1,2,3,.a=1, 2, 3, .a=1, 4, 5};
}
Kaz Kylheku
2024-10-13 23:33:04 UTC
Permalink
Post by Thiago Adams
The algorithm for C initialization as described in the standard and
implemented in gcc allow this.
struct X{
int a,b,c;
};
int main()
{
struct X x = {.a=1,2,3,.a=1, 2, 3};
}
https://godbolt.org/z/7naedbEM6
Basically, when a designed initializer is found the "cursor" goes to
that member and the following members are initialized in order.
I do not suspect that therw is an observable order. I.e. as
in a required order considered observable behavior.
--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @***@mstdn.ca
Tim Rentsch
2024-10-14 05:00:39 UTC
Permalink
Post by Thiago Adams
The algorithm for C initialization as described in the standard
and implemented in gcc allow this.
struct X{
int a,b,c;
};
int main()
{
struct X x = {.a=1,2,3,.a=1, 2, 3};
}
https://godbolt.org/z/7naedbEM6
Basically, when a designed initializer is found the "cursor" goes
to that member and the following members are initialized in
order.
I do not suspect that therw is an observable order. I.e. as
in a required order considered observable behavior.
Have you checked to C standard to see what it says about that?
Thiago Adams
2024-10-14 11:14:40 UTC
Permalink
Post by Tim Rentsch
Post by Thiago Adams
The algorithm for C initialization as described in the standard
and implemented in gcc allow this.
struct X{
int a,b,c;
};
int main()
{
struct X x = {.a=1,2,3,.a=1, 2, 3};
}
https://godbolt.org/z/7naedbEM6
Basically, when a designed initializer is found the "cursor" goes
to that member and the following members are initialized in
order.
I do not suspect that therw is an observable order. I.e. as
in a required order considered observable behavior.
Have you checked to C standard to see what it says about that?
I think these parts are relevant.

"
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.167) 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.168)
"

The initialization shall occur in initializer list order, each
initializer provided for a particular subobject
overriding any previously listed initializer for the same subobject;170)
all subobjects that are not
initialized explicitly are subject to default initialization.
"

"170: Any initializer for the subobject which is overridden and so not
used to initialize that subobject may not be evaluated at all. "


This last part made me create this sample in GCC. Reading it seems like
it could potentially use the previous value.


#include <stdio.h>

struct X {
int a, b;
};

int main()
{
const struct X x2 = { .a=1, .b = x2.a, .a =2 };
printf("a=%d b=%d", x2.a, x2.b); //a=2 b=2
}

https://godbolt.org/z/6K7xKqh86



clang shows when something is overridden.
Thiago Adams
2024-10-15 11:12:35 UTC
Permalink
Post by Tim Rentsch
Post by Thiago Adams
The algorithm for C initialization as described in the standard
and implemented in gcc allow this.
struct X{
      int a,b,c;
};
int main()
{
      struct X x = {.a=1,2,3,.a=1, 2, 3};
}
https://godbolt.org/z/7naedbEM6
Basically, when a designed initializer is found the "cursor" goes
to that member and the following members are initialized in
order.
  I do not suspect that therw is an observable order.  I.e. as
  in a required order considered observable behavior.
Have you checked to C standard to see what it says about that?
I'm not only interested in this part, but since it raised some doubts, I
decided to do some checks

#include <stdio.h>

struct X {
int i;
};

int f() {
printf("f");
return 1;
}

int main() {
struct X x = {.i = f(), .i = f() };
}

https://godbolt.org/z/rf984cGMM

There is a warning in this sample and f is called just once.
Thiago Adams
2024-10-15 11:14:46 UTC
Permalink
Post by Thiago Adams
Post by Tim Rentsch
Post by Thiago Adams
The algorithm for C initialization as described in the standard
and implemented in gcc allow this.
struct X{
      int a,b,c;
};
int main()
{
      struct X x = {.a=1,2,3,.a=1, 2, 3};
}
https://godbolt.org/z/7naedbEM6
Basically, when a designed initializer is found the "cursor" goes
to that member and the following members are initialized in
order.
  I do not suspect that therw is an observable order.  I.e. as
  in a required order considered observable behavior.
Have you checked to C standard to see what it says about that?
I'm not only interested in this part, but since it raised some doubts, I
decided to do some checks
#include <stdio.h>
struct X {
    int i;
};
int f() {
    printf("f");
    return 1;
}
int main() {
    struct X x = {.i = f(), .i = f() };
}
https://godbolt.org/z/rf984cGMM
There is a warning in this sample and f is called just once.
Forgot to say that I didn't find this part on the standard.
I think initialization is also very superficial on books.
Kaz Kylheku
2024-10-15 20:30:43 UTC
Permalink
Post by Thiago Adams
Post by Thiago Adams
int main() {
    struct X x = {.i = f(), .i = f() };
}
https://godbolt.org/z/rf984cGMM
There is a warning in this sample and f is called just once.
Forgot to say that I didn't find this part on the standard.
I think initialization is also very superficial on books.
The current public draft, which I think is still N3047, does
address the issue of repeated mentions of the same subobject in
a designated initializer:

The initialization shall occur in initializer list order, each
initializer provided for a particular subobject overriding any
previously listed initializer for the same subobject.(184)

Since the second .i = f() overrides the previously listed .i = f(),
there is only one initialization of .i.

It is not specified whether both calls to f() occur; i.e.
is the initializing expression of the overridden initializer still
evaluated?

The referenced footnoted 184 address itself to this question.
But not only is the footnote not normative text, as you know,
it uses the phrase "might not", thus only clarifying that this
aspect is not specified. f could be called twice or only once:

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

Don't write code that initializes subobjects more than once, or else if
you do, don't have side effects in the initializing expressions such
that the program depends on all of them being invoked.

The implementation's warning is a good idea.
--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @***@mstdn.ca
Loading...