Есть ли способ получить предупреждение о неправильном поведении назначенных инициализаторов?
C99 ввел концепцию назначенных инициализаторов для структур. Так, например, учитывая:
typedef struct {
int c;
char a;
float b;
} X;
Я мог бы инициализировать как: X foo = {.a = '\1', .b = 2.0F, .c = 4};
и звонит: printf("c = %d\na = %hhu\nb = %f", foo.c, foo.a, foo.b);
будет выводить:
с = 4
а = 1
b = 2,000000
Как упомянуто здесь, это имеет "удивительное поведение" присвоения c
затем a
затем b
, независимо от порядка моих назначенных инициализаторов.
Это становится реальной проблемой, если у меня есть такие функции:
int i = 0;
int f() {
return ++i;
}
int g() {
i += 2;
return i;
}
int h() {
i += 4;
return i;
}
И я хочу инициализировать так: X foo = {.a = (char)f(), .b = g(), .c = h()};
Теперь, когда я делаю: printf("c = %d\na = %hhu\nb = %f", foo.c, foo.a, foo.b);
Я получил:
с = 4
а = 5
б = 7,000000
Проблема в том, что не было предупреждения о том, что мой порядок инициализации не был соблюден. Есть ли предупреждение или что-то, что я могу включить для этого?
[ Живой пример]
2 ответа
... нет предупреждения, что мой порядок инициализации не был соблюден.
Конкретный порядок инициализации - это ожидание, основанное на чем-то ином, чем указано в стандарте. (как указано в комментариях)
C99 раздел 6.7.9, стр. 23: 23 Оценки выражений списка инициализации неопределенно упорядочены по отношению друг к другу, и, таким образом, порядок возникновения побочных эффектов не определен. [акцент мой]
Поэтому здесь нет никаких проблем, кроме неопределенного (или неопределенного) поведения. Очень похоже на другие поведения C, такие как неоднозначность с порядком оценки аргументов функции.
РЕДАКТИРОВАТЬ
С99 может сказать об этом следующее:
из C99 §6.5.2.2p10:
Порядок вычисления аргументов функции не определен. Порядок вычисления указателя функции, фактических аргументов и подвыражений внутри фактических аргументов не указан, но перед фактическим вызовом есть точка последовательности.
[акцент мой]
То, что вы предпочли бы предупреждение (которое вы хорошо заявили +1) - это другое дело. Я не уверен, насколько практичным было бы предоставить предупреждение для каждого- неопределенного- поведения- в языках C/C++.
Интересно отметить некоторые из высказанных предположений / мнений в этом обсуждении, почему стандарты C++ не включают в себя Назначенные инициализаторы. (Еще)...
... C++ больше заинтересован в придании гибкости стороне дизайнера типа, так что дизайнеры могут упростить правильное использование типа и затруднить его неправильное использование.
Лучшая (читай: разумная) вещь, которую вы можете сделать в C, это объявить три временные переменные const, прежде чем инициализировать структуру. Их порядок декларирования является порядком оценки их инициализаторов.
Что-то вроде этого:
const char a = f();
const float b = g();
const int c = h();
X foo = {.a = a, .b = b, .c = c};
В этом случае порядок вызовов функций и намерения программиста понятны.