Я только что провел до часу ночи, отслеживая ошибку в моем коде, и то, что я нашел, меня очень удивило. Фактический код очень сложен, включая объединения структур, содержащих объединения структур и т. д., но я свел проблему к следующему упрощенному случаю отказа.
Происходит следующее: компилятор [gcc 5.4.0] меняет порядок выполнения назначенных инициализаторов, чтобы он соответствовал порядку их появления в структуре. Это не вызывает никаких проблем, пока вы инициализируете структуру с константами или переменными, которые не зависят от порядка. Проверьте следующий код. Это показывает, что компилятор явно переупорядочивает назначенные инициализаторы:
#include <stdio.h>
typedef const struct {
const size_t First_setToOne;
const size_t Second_setToThree;
const size_t Third_setToTwo;
const size_t Fourth_setToFour;
} MyConstStruct;
static void Broken(void)
{
size_t i = 0;
const MyConstStruct myConstStruct = {
.First_setToOne = ++i,
.Third_setToTwo = ++i,
.Second_setToThree = ++i,
.Fourth_setToFour = ++i,
};
printf("\nBroken:\n");
printf("First_setToOne should be 1, is %zd\n", myConstStruct.First_setToOne );
printf("Second_setToThree should be 3, is %zd\n", myConstStruct.Second_setToThree);
printf("Third_setToTwo should be 2, is %zd\n", myConstStruct.Third_setToTwo );
printf("Fourth_setToFour should be 4, is %zd\n", myConstStruct.Fourth_setToFour );
}
static void Fixed(void)
{
size_t i = 0;
const size_t First_setToOne = ++i;
const size_t Third_setToTwo = ++i;
const size_t Second_setToThree = ++i;
const size_t Fourth_setToFour = ++i;
const MyConstStruct myConstStruct = {
.First_setToOne = First_setToOne ,
.Third_setToTwo = Third_setToTwo ,
.Second_setToThree = Second_setToThree,
.Fourth_setToFour = Fourth_setToFour ,
};
printf("\nFixed:\n");
printf("First_setToOne should be 1, is %zd\n", myConstStruct.First_setToOne );
printf("Second_setToThree should be 3, is %zd\n", myConstStruct.Second_setToThree);
printf("Third_setToTwo should be 2, is %zd\n", myConstStruct.Third_setToTwo );
printf("Fourth_setToFour should be 4, is %zd\n", myConstStruct.Fourth_setToFour );
}
int main (int argc, char *argv[])
{
(void)argc;
(void)argv;
Broken();
Fixed();
return(0);
}
Результат выглядит следующим образом:
Broken:
First_setToOne should be 1, is 1
Second_setToThree should be 3, is 2
Third_setToTwo should be 2, is 3
Fourth_setToFour should be 4, is 4
Fixed:
First_setToOne should be 1, is 1
Second_setToThree should be 3, is 3
Third_setToTwo should be 2, is 2
Fourth_setToFour should be 4, is 4
Я подозревал оптимизатор, но я попробовал тот же код, используя все возможные уровни оптимизации, и переупорядочение все еще происходит. Так что эта проблема в базовом компиляторе.
У меня есть решение, так что это скорее предупреждение для других и общий вопрос.
Кто-нибудь еще видел или заметил эту проблему?
Это ожидаемое/заданное поведение?