Есть ли способ получить предупреждение о неправильном поведении назначенных инициализаторов?

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};

В этом случае порядок вызовов функций и намерения программиста понятны.

Другие вопросы по тегам