Рабочая инициализация будет:
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);
}
Эта вторая версия инициализации компилируется без проблем в каждом протестированном компиляторе, поэтому справедливо предположить, что он более переносим.
Первая версия, вероятно, более легко читаема и позволяет легче идентифицировать ошибки при инициализации, обозначенные инициализаторы показаны явно.