Агрегировать инициализацию, установить указатель на тот же элемент структуры - PullRequest
7 голосов
/ 12 февраля 2020

Можно ли использовать агрегатную инициализацию, чтобы указатель aptr указывал на a, который является членом того же struct?

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

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

Вопрос касается C и C++.

1 Ответ

8 голосов
/ 12 февраля 2020

Рабочая инициализация будет:

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

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

Рабочие образцы:

C11 GNU

C ++ 2a GNU

Относительно правильности инициализации:

Для C:

Оценки выражений списка инициализации неопределенно упорядочены по отношению друг к другу, и, следовательно, порядок возникновения побочных эффектов не определен.

Для C ++:

В списке инициализаторов списка фигурных инициализаций предложения инициализатора, включая любые, которые являются результатом расширений пакета ([temp.variadic]), оцениваются в порядке их появления . То есть каждое вычисление значения и побочный эффект, связанный с данным предложением инициализатора, упорядочивается перед каждым вычислением значения и побочным эффектом, связанным с любым предложением инициализатора, которое следует за ним в списке через запятую списка инициализатора .

Однако, несмотря на различия, которые мы можем наблюдать, порядок вычисления выражений в данном случае не имеет значения, поскольку вы фактически не получаете доступ к значению s.a, только его адрес, который доступен в данный момент.

Так что это правильная инициализация как для C и C++.


Что следует отметить с этим кодом, в MSVC произошла ошибка компиляции:

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

Использование std:c++latest ошибка меняется на:

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

Однако компиляторы, такие же старые, как clang 3.1 и C++03 GNU, компилируются в порядке с предупреждений нет.

Как говорится, второе решение было бы:

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

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

Эта вторая версия инициализации компилируется без проблем в каждом протестированном компиляторе, поэтому справедливо предположить, что он более переносим.

Первая версия, вероятно, более легко читаема и позволяет легче идентифицировать ошибки при инициализации, обозначенные инициализаторы показаны явно.

...