在我们的代码中,我们曾经有类似的东西:
*(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兆字节,而且只能在堆上存在!
我们已经使用了我们自己的'初始化'功能来明确设置成员,但这很难看并且是一个维护问题。我不认为memset是一个合适的解决方案,因为我不知道0的位值是该类型的适当零值(我知道,但是你知道,但是你有;我不介意编译器会这样做,因为可以知道)
初始化像这样的大型结构的“正确”或至少是最好的方法是什么?
更进一步澄清为什么我认为memset不是解决方案:未明确初始化的成员的初始化规则与静态初始化相同,如下所示: - 如果它有指针类型,则将其初始化为空指针; - 如果它有算术类型,则初始化为(正或无符号)零; ...
'memset'会将内存设置为位模式零,这不一定是一回事。想象一下不使用IEEE浮点数的系统。不寻常,但由C支持.0.0的表示不一定意味着“全位为零”,它可以是处理器的任何方便。
答案 0 :(得分:21)
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!我今天学到了一些东西:)
答案 1 :(得分:6)
如果您不想使用memset,您可以随时声明结构的静态副本并使用memcpy,这将提供类似的性能。这将为您的程序添加4兆,但可能比设置单个元素更好。
那就是说,如果GCC使用的是memset,之前已经足够好了,我建议现在已经足够好了。
答案 2 :(得分:5)
正如其他人所说,memset是要走的路。但是,不在C ++对象上使用memset,特别是那些使用虚方法的对象。 sizeof( foo )
将包含虚函数指针表,并对其执行memset会导致严重的悲伤。
如果memset本身没有解决问题,只需执行一个memset然后然后初始化任何非零的成员(即你的非IEEE浮点值)。
答案 3 :(得分:4)
私有初始化函数并不是一个很好的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的问题。
答案 4 :(得分:0)
许多谈论内存集而没有谈论calloc。我宁愿使用为此用例设计的calloc(如果我错了,请发表评论):
calloc()函数为每个大小为字节的nmemb元素数组分配内存,并返回指向已分配内存的指针。内存设置为零。如果nmemb或size为0,则calloc()返回NULL或一个唯一的指针值,该值以后可以成功传递给free()。
示例:
#include <stdlib.h> // calloc header
#include <stdio.h> // printf header
void *init_heap_array(int elem_nb, int elem_size) {
void *ptr;
if (!(ptr = calloc(elem_nb, elem_size)))
return NULL;
return ptr;
}
void set_int_value_at_index(int *ptr, int value, int i) {
ptr[i] = value;
}
void print_int_array_until(int *ptr, const int until) {
for (int i = 0; i < until; i++)
printf("%02d ", ptr[i]);
putchar('\n');
}
int main(void) {
const int array_len = 300000;
int *n;
if (!(n = init_heap_array(array_len, sizeof(int))))
return 1;
print_int_array_until(n, 5);
set_int_value_at_index(n, 42, 1);
print_int_array_until(n, 5);
return 0;
}
答案 5 :(得分:-2)
嗯 - 首先制作一个init函数并明确地设置每个成员是正确的 - 它是OO语言中构造函数的工作方式。
和第二 - 有没有人知道实现非IEEE浮点数的硬件? - 也许Commodore 64或somethig; - )