全局静态变量的顺序是否保留在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,则在编译时会失败