全局静态变量的顺序是否保留在C中?
考虑:全局静态变量的顺序是否保留在C中?,c,static,C,Static,考虑: typedef struct MS{ uint8_t maxlen; uint8_t curlen; char buf[1]; // dummy length } MS; MS ms7; char ms7data[6]; /* make storage space */ MS ms100; char ms100data[99]; /* make storage space */ int main() { /* ...
typedef struct MS{
uint8_t maxlen;
uint8_t curlen;
char buf[1]; // dummy length
} MS;
MS ms7;
char ms7data[6]; /* make storage space */
MS ms100;
char ms100data[99]; /* make storage space */
int main() {
/* .... */
}
其目的是,比如说,ms7.buf
将不仅访问它自己的char,而且访问下面的6,相当于它被声明为char buf[7]
。我的代码将正确初始化MS
字段,并且永远不会访问变量ms7data
为了使其工作,我需要确保编译器将尊重(全局、静态)变量的顺序。我可以相信吗?(我知道这对结构字段是有保证的)。不,顺序不保证。对象可以四处移动、优化,等等 事实上,对于一个正确的程序来说,不可能确定静态变量的顺序(假设地址空间上甚至定义了一个顺序,而分段体系结构等可能没有这样的顺序) 如果要保证多个全局对象按顺序出现,则必须将它们放置在结构中,例如:
static struct
{
MS ms7;
char ms7data[6]; /* make storage space */
MS ms100;
char ms100data[99];
} globals;
请注意,在这种情况下,结构成员之间可能仍然存在填充,但是您可以使用编译器扩展来避免这种情况,或者执行
sizeof
检查。否,顺序不保证。对象可以四处移动、优化,等等
事实上,对于一个正确的程序来说,不可能确定静态变量的顺序(假设地址空间上甚至定义了一个顺序,而分段体系结构等可能没有这样的顺序)
如果要保证多个全局对象按顺序出现,则必须将它们放置在结构中,例如:
static struct
{
MS ms7;
char ms7data[6]; /* make storage space */
MS ms100;
char ms100data[99];
} globals;
请注意,在这种情况下,结构成员之间可能仍然存在填充,但您可以使用编译器扩展来避免这种情况,或者执行
sizeof
检查。否。您不能依赖于此。试图访问MS.buf[i]
时i
大于1
是未定义的行为。@CongMa:好的,但是如果变量放在一个结构中,它将是合法的,行为也不会未定义,对吗?@CongMa你的意思是i
大于0
(索引0)@leonbloy在除灵活数组成员外的所有情况下,访问数组的边界是未定义的。我从未见过在全局数组中使用flexible数组成员,但也许是这样OK@M.M:如果在分配的存储之外访问灵活阵列成员,则它们实际上是UB,因此此处没有更改。不确定是否可以全局使用这样的结构。你肯定不能初始化它,那么你该如何定义数组的大小呢?不,你不能依赖它。试图访问MS.buf[i]
时i
大于1
是未定义的行为。@CongMa:好的,但是如果变量放在一个结构中,它将是合法的,行为也不会未定义,对吗?@CongMa你的意思是i
大于0
(索引0)@leonbloy在除灵活数组成员外的所有情况下,访问数组的边界是未定义的。我从未见过在全局数组中使用flexible数组成员,但也许是这样OK@M.M:如果在分配的存储之外访问灵活阵列成员,则它们实际上是UB,因此此处没有更改。不确定是否可以全局使用这样的结构。您完全可以不初始化它,那么如何定义数组的大小呢?谢谢。关于填充,我知道这一点,但在这种情况下(我不访问虚拟存储变量),我认为这无关紧要(ms7.buf[1]
将在ms7data[0]
之前,但谁在乎呢)。@leonbloy嗯,填充字节不能可靠地存储值(例如,优化编译器可以重复使用填充来存储临时变量)。您可以使用宏动态定义结构(和关联实例)。另一种方法(您可能知道,但可能值得一提)是动态分配“过大”的内存块(MS*ms7=malloc(sizeof(MS)+6)
)。您还可以在结构中使用stddef.h
中的offsetof
来验证结构中成员的填充和位置。是的,或者您可以static\u断言(sizeof globals==sizeof(MS)*2+6+99)
其中static\u assert
是一个宏,如果参数为false,则在编译时会失败。关于填充,我知道这一点,但在这种情况下(我不访问虚拟存储变量),我认为这无关紧要(ms7.buf[1]
将在ms7data[0]
之前,但谁在乎呢)@leonbloy嗯,填充字节中不能可靠地存储值(例如,优化编译器可以重复使用填充来存储临时变量)。而且您可以使用宏动态定义结构(和关联实例)。另一种方法(您可能知道,但可能值得一提)是动态分配“过大”内存块(MS*ms7=malloc(sizeof(MS)+6)
)。您也可以在结构中使用stddef.h
中的offsetof
来验证结构中成员的填充和位置。是的,或者您可以静态断言(sizeof globals==sizeof(MS)*2+6+99)
其中static\u assert
是一个宏,如果参数为false,则在编译时会失败