Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Aggregate initialization, set member pointer to same struct member

Tags:

c++

c

struct

c++20

c11

Is it possible to use aggregate initialization to make a pointer aptr point to a which is a member of the same struct ?

struct S {
  int a;
  int* aptr;
};

int main() {
  S s = {
    .a = 3,
    .aptr = &a //point aptr to a
  };
  return 0;
}

The question is for both C and C++.

like image 785
Samantha Avatar asked Feb 12 '20 14:02

Samantha


Video Answer


1 Answers

A working initialization would be:

struct S {
  int a;
  int* aptr;
};

int main() {
    struct S s = {.a = 3, .aptr = &s.a};
    printf("%d", *s.aptr);
}

Working samples:

C11 GNU

C++2a GNU

Regarding the correctness of the initialization:

For C:

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.

For C++:

Within the initializer-list of a braced-init-list, the initializer-clauses, including any that result from pack expansions ([temp.variadic]), are evaluated in the order in which they appear. That is, every value computation and side effect associated with a given initializer-clause is sequenced before every value computation and side effect associated with any initializer-clause that follows it in the comma-separated list of the initializer-list.

However, despite the differences we can observe, the order in which the expressions are evaluated does not seem matter in this case, since you're not actually accessing the value of s.a, just its address which is accessible at this point.

So this is a correct initialization both for C and C++.


Something to note with this code, in MSVC, there is a compilation error in C++:

use of designated initializers requires at least '/std:c++latest'

Using std:c++latest the error changes to:

designated and non-designated initializers is nonstandard in C++

However, compilers that range from clang 3.1 to clang 10.0 and gcc 4.9.0 to gcc 10.0 with C++03 to C++2a compile fine with no warnings.

Designated initializers where introduced in C++20, so it is actually correct not to accept them, as MSVC still does not accept /std:c++20, it is not possible to use them yet, it also looks like gcc and clang always provided support for these initializers.

That being said, a second solution would be:

struct S {
    int a;
    int* aptr;
};

int main() {
    struct S s = { 3, &s.a };
    printf("%d", *s.aptr);
}

This second version of initialization compiles with no issues in every compiler tested, so it's fair to assume that it is more portable.

The first version is probably more easily readable and allows for a easier identification of errors in initialization, one of the advantages of designated initializers.

like image 148
anastaciu Avatar answered Oct 26 '22 12:10

anastaciu