我只花了大约凌晨1点来追踪代码中的错误,我发现的确让我感到惊讶。实际的代码非常复杂,涉及包含结构联合等的结构的联合,但我已经将问题提炼到以下简化的失败案例。
正在发生的事情是编译器[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
我怀疑优化器,但我尝试使用每个可能的优化级别的相同代码,并且仍然会发生重新排序。所以这个问题在基础编译器中。
我有一个解决方案,所以这更像是对其他人的警告和一般性问题。
有没有人见过或发现过这个问题?
这是预期/指定的行为吗?
答案 0 :(得分:10)
C99标准允许以任何顺序应用副作用:
6.7.8.23:未指定初始化列表表达式中出现任何副作用的顺序。
脚注进一步澄清:
特别是,评估顺序不必与子对象初始化的顺序相同。