初始化非常大的结构的正确方法是什么?

在我们的代码中,我们曾经有这样的事情:

*(controller->bigstruct) = ( struct bigstruct ){ 0 }; 

这曾经很好用,然后我们升级了GCC版本并突然开始看到堆栈溢出。 看看程序集,旧的GCC代码(2.x)基本上是这样做的:

 memset(controller->bigstruct, 0, sizeof(struct bigstruct)); 

新的GCC(3.4.x)正在这样做

  struct bigstruct temp = { 0 }; controller->bigstruct = temp; 

在审查了C99规范后,我明白了为什么; C99基本上要求堆栈上存在匿名结构。 这是一个很好的概念,但是这个结构大了4兆字节,并且只能在堆上存在!

我们已经使用了我们自己的“初始化”function来明确设置成员,但这很丑陋并且是一个维护问题。 我不认为memset是一个合适的解决方案,因为我不知道0的位值是该类型的适当零值(我知道,但是你知道,但是你有;我不介意编译器做到了,因为它可以知道)

初始化像这样的大型结构的“正确”或至少是最好的方法是什么?

为了进一步阐明我认为memset不是解决方案的原因:未明确初始化的成员的初始化规则与静态初始化相同,如下所示: – 如果它有指针类型,则初始化为空指针; – 如果它有算术类型,则初始化为(正或无符号)零; …

‘memset’会将内存设置为位模式零,这不一定是一回事。 想象一下不使用IEEE浮点数的系统。 不寻常,但由C支持.0.0的表示不一定意味着“全位为零”,它可以是处理器的任何方便。

memset是要走的路。 你没有很多选择。

做类似的事情:

 #define InitStruct(var, type) type var; memset(&var, 0, sizeof(type)) 

所以你只需要:

 InitStruct(st, BigStruct); 

然后像往常一样使用st …

我不明白“0”不是结构的有效“0”类型。 “批量初始化”结构的唯一方法是将其所有内存设置为一个值; 否则你将需要额外的逻辑来告诉它使用每个成员的特定位模式。 要使用的最佳“通用”位模式为0。

此外 – 这与您在执行时使用的逻辑相同

 *(controller->bigstruct) = *( struct bigstruct ){ 0 }; 

所以我不会不情愿地使用它:)

对这篇文章的第一个评论让我在打电话给他和白痴​​之前做了一些研究,我发现了这个:

http://www.lysator.liu.se/c/c-faq/c-1.html

很有意思; 如果我可以投票评论我会:)

话虽这么说 – 如果你想要使用非0空值来定位古老的架构,你唯一的选择仍然是对某些成员进行手动初始化。

谢谢Thomas Padron-McCarthy! 我今天学了些新东西 :)

如果您不想使用memset,您可以随时声明结构的静态副本并使用memcpy,这将提供类似的性能。 这将为您的程序添加4兆,但可能比设置单个元素更好。

也就是说,如果GCC使用的是memset,之前它已经足够好了,我建议它现在已经足够好了。

正如其他人所说,memset是要走的路。 但是, 不要在C ++对象上使用memset,尤其是那些使用虚方法的对象。 sizeof( foo )将包含虚函数指针表,并在其上执行memset将导致严重的悲伤。

如果memset本身没有解决问题,只需执行memset 然后初始化任何非零的成员(即非IEEE浮点值)。

私有初始化函数并不是一个很好的OO方法来初始化对象(结构)。 我假设你的结构不是4MB的指针,所以我认为解决方案应该是这样的:

 void init_big_struct(struct bigstruct *s) { memset(s, 0, sizeof(struct bigstruct)); s->some_pointer = NULL; // Multiply this as needed } 

另一方面,我们的代码运行在20多个嵌入式操作系统和大量不同的硬件上,从不会遇到任何问题只需memset的结构。

嗯 – 首先制作一个init函数并明确地设置每个成员是正确的 – 它是OO语言中构造函数的工作方式。

第二 – 有没有人知道实现非IEEE浮点数的硬件? – 也许Commodore 64或somethig 😉