如何在 C 中声明后初始化结构数组

How to initialize array of structures after declaration in C

有没有办法在声明后初始化整个结构数组(可能使用复合文字)?

typedef struct
{
    int a;
    int b;
} tStruct;

/* Array of structures in declared in global scope, but not initialized */
tStruct myStruct[3];

void init()
{
  /* We want to initizlize the array with specific values*/
  
  /* using compound literals to initialize the whole array doesn't work */
  myStruct = (tStruct[])
  {
      {1, 2},
      {3, 4},
      {5, 6}
  }; 
}

数组不是 R 值,因此您不能通过赋值复制它们。但是你可以使用 memcpy

#include <string.h>
void init(void)
{
    memcpy(&myStruct,(tStruct[]) { {1, 2}, {3, 4}, {5, 6} }, sizeof(myStruct)); 
}

优化编译器生成的代码应该不会比你得到的代码差多少

void init2(void)
{
    myStruct[0] = (tStruct){1,2};
    myStruct[1] = (tStruct){3,4};
    myStruct[2] = (tStruct){5,6};
}

void init3(void)
{
    myStruct[0].a = 1, myStruct[0].b = 2;
    myStruct[1].a = 3, myStruct[1].b = 4;
    myStruct[2].a = 5, myStruct[1].b = 6;
}

Gcc 和 clang 能够很好地省略不必要的复合变量,例如直接分配单个组件。

https://gcc.godbolt.org/z/j9f37j

memcpy 方法的最大缺点是它有点脆弱且类型不安全(如果违反了非强制类型兼容性,可能会导致越界 reads/writes)。

如果你的 C 方言有 __typeof,那么通过一些宏技巧你应该能够几乎绕过这个 C 语言限制:

#include <string.h>
#define assignAnything(DestPtr,SrcPtr) ((void)((__typeof(SrcPtr)){0} = (__typeof(DestPtr)){0}) /*typecheck*/, memcpy(DestPtr, SrcPtr, sizeof(*(DestPtr))))

/* A Ptr-less version:
#define assignAnything2(Dest,Src) ((void)((__typeof(&(Src))){0} = (__typeof(&(Dest))){0}), memcpy(&(Dest), &(__typeof(Src)){Src}, sizeof(Dest)))
doesn't always work, unfortunately */

int main()
{
    int d[3][2][1]={0};
    int const s[3][2][1] = {0};
    assignAnything(&d,&s); //works
    #if NOPE
    assignAnything(&s,&d); //will (correctly) compile-time fail because s has more qualifs (const) than d
    #endif
}

不,这不起作用,因为您不能将一个数组分配给另一个数组。

但您可以使用 memcpy 来绕过它

void init()
{
   tStruct data[3] = {
      {1, 2},
      {3, 4},
      {5, 6}
   };
   memcpy(mystruct, data, sizeof(mystruct));
}

但是,注意数据的大小必须完全匹配。

对于数组,复合文字只对语句声明起作用。之后您必须使用单独的赋值、循环、memcpy() 或 memset() 来初始化数组和结构。

示例,获得相同的结果:

typedef struct
{
    int a;
    int b;
} tStruct;

/* Array of structures in declared in global scope, but not initialized */
tStruct myStruct[3];

void init()
{
  /* Initizlize the array with specific values*/
  int i;
  const tStruct second_element = { 3, 4 };

  // member by member...
  myStruct[0].a = 1;
  myStruct[0].b = 2;

  // using struct copy.
  myStruct[1] = second_element;

  // or a loop...
  for (i = 2; i < 3; ++i)  // I know, there are only 3 elmments, but you get 
                           // the idea.. 
  {
      myStruct[i].a = (2 * i) + 1;
      myStruct[i].b = myStruct[i].a + 1;
  }
}