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

时间:2021-10-11 20:16:45

In our code we used to have something like this:

在我们的代码中,我们曾经有这样的东西:

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

This used to work great, and then we upgraded versions of GCC and suddenly started seeing stack overflows. Looking at the assembly, the old GCC code (2.x) was basically doing this:

这以前工作得很好,然后我们升级了GCC的版本,然后突然看到堆栈溢出。看看大会,旧的GCC代码(2.x)基本上是这样做的:

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

The new GCC (3.4.x) was doing this

新的GCC (3.4.x)就是这么做的

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

After reviewing the C99 spec, I could see why; C99 basically requires that anonymous structures exist on the stack. It's a good concept, but this structure was 4 Megabytes large, and only ever intended to exist on heap!

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

We've resorted to making our own 'initialize' function that explicitly sets the members, but that's ugly and a maintenance headache. I don't consider memset a proper solution, because I can't know that a bit-value of 0 is an appropriate zero value for the type ( nit-picking, I know, but there you are; I don't mind that the compiler does it, because it can know )

我们采用了自己的“初始化”函数来显式地设置成员,但这很难看,而且维护起来很麻烦。我不认为memset是一个合适的解,因为我不知道0的位值对于类型来说是一个合适的零值(挑剔,我知道,但这就是;我不介意编译器这么做,因为它知道)

What is the "correct", or at least best, way to initialize a large structure like this?

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

To furthur clarify why I think memset isn't a solution: The rules of initialization of members not explicitly initialized are the same as static initialization, and are as follows: - If it has pointer type, it is initialized to a null pointer; - If it has arithmetic type, it is initialized to ( positive or unsigned ) zero; ...

进一步说明为什么我认为memset不是一个解决方案:未显式初始化的成员的初始化规则与静态初始化相同,如下:-如果它有指针类型,则初始化为空指针;-如果具有算术类型,则初始化为(正的或无符号的)零;…

'memset' will set the memory to bit-pattern zero, which isn't necessarily the same thing. Imagine a system that doesn't use IEEE floating point numbers. Unusual, but supported by C. The representation of 0.0 doesn't have to mean "all-bits zero", it could be anything convenient to the processor.

“memset”将内存设置为位模式0,这并不一定是一回事。想象一个不使用IEEE浮点数的系统。不寻常,但由c支持。0的表示不需要表示“全位零”,它可以是任何方便的处理器。

5 个解决方案

#1


21  

memset is the way to go. You do not have many alternatives.

memset就是这样。你没有很多选择。

Do something like:

做些什么:

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

So that you only have to:

所以你只需要:

InitStruct(st, BigStruct);

And then use st as usual...

然后像往常一样使用st……

I do not get how "0" is not a valid "0" type for a struct. The only way to "mass initialize" a struct is to set all of its memory to a value; otherwise you would have to make extra logic to tell it to use a specific bit pattern per member. The best "generic" bit pattern to use is 0.

我不知道“0”如何不是结构体的有效“0”类型。“初始化”结构体的唯一方法是将其所有内存设置为一个值;否则,您将不得不使用额外的逻辑告诉它使用每个成员的特定位模式。使用的最佳“通用”位模式为0。

Besides - this is the same logic that you used when doing

此外,这和你做的时候用的逻辑是一样的

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

Therefore I don't get your reluctance to use it :)

因此,我不明白你为什么不愿意使用它:

The first comment to this post made me do some research before I called him and idiot and I found this:

这篇文章的第一条评论让我在给他打电话之前做了一些调查,我发现:

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

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

Very interesting; if I could vote-up a comment I would :)

非常有趣的;如果我能得到一个评论,我会:)

That being said - your only option if you want to target archaic architectures with non-0 null values is still to do manual initialization to certain members.

这就是说,如果您想要使用非0值的过时架构,那么您的惟一选项仍然是对某些成员进行手工初始化。

Thanks Thomas Padron-McCarthy! I learned something new today :)

谢谢托马斯Padron-McCarthy !我今天学到了一些新东西

#2


6  

If you don't want to use memset, you could always declare a static copy of your struct and use memcpy, which will give similar performance. This will add 4 megs to your program but is probably better than setting individual elements.

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

That said, if GCC was using memset, and it was good enough previously, I would suggest it is good enough now.

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

#3


5  

As others have said, memset is the way to go. However, don't use memset on C++ objects, particularly those with virtual methods. The sizeof( foo ) will include the table of virtual function pointers, and doing a memset on that will cause serious grief.

正如其他人所说的,memset是一条路。但是,不要在c++对象上使用memset,特别是使用虚拟方法的对象。sizeof(foo)将包含虚拟函数指针的表,并且在其上做一个memset会引起严重的悲痛。

If memset doesn't solve the problem by itself, simply do a memset and then initialize any members that should be non-zero (i.e. your non-IEEE floating point values).

如果memset本身不能解决问题,只需做一个memset,然后初始化任何非零的成员(即非ieee浮点值)。

#4


4  

Private initialization function is not ugly rather a good OO way to initialize objects (structs). I assume that your structure is not 4MB of pointers, so i would assume that the solution should be like this:

私有初始化函数并不难看,而是一种很好的对象初始化方法。我假设你的结构不是4MB的指针,所以我假设解决方案应该是这样的:

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

From other hand our code is running on more then 20 embedded operating systems and large number of different hardwares, never meet any problem with just memset of the struct.

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

#5


-2  

hmm - first of all making an init function and setting each member explicitly IS THE RIGHT THING - it,s the way constructors in OO languages work.

嗯,首先创建一个init函数并显式地设置每个成员是正确的——这是OO语言中构造函数的工作方式。

and second - does anyone know a hardware that implements non IEEE floating point numbers ? - perhaps Commodore 64 or somethig ;-)

第二,有人知道实现非IEEE浮点数的硬件吗?-可能是64名准将或什么;-)

#1


21  

memset is the way to go. You do not have many alternatives.

memset就是这样。你没有很多选择。

Do something like:

做些什么:

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

So that you only have to:

所以你只需要:

InitStruct(st, BigStruct);

And then use st as usual...

然后像往常一样使用st……

I do not get how "0" is not a valid "0" type for a struct. The only way to "mass initialize" a struct is to set all of its memory to a value; otherwise you would have to make extra logic to tell it to use a specific bit pattern per member. The best "generic" bit pattern to use is 0.

我不知道“0”如何不是结构体的有效“0”类型。“初始化”结构体的唯一方法是将其所有内存设置为一个值;否则,您将不得不使用额外的逻辑告诉它使用每个成员的特定位模式。使用的最佳“通用”位模式为0。

Besides - this is the same logic that you used when doing

此外,这和你做的时候用的逻辑是一样的

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

Therefore I don't get your reluctance to use it :)

因此,我不明白你为什么不愿意使用它:

The first comment to this post made me do some research before I called him and idiot and I found this:

这篇文章的第一条评论让我在给他打电话之前做了一些调查,我发现:

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

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

Very interesting; if I could vote-up a comment I would :)

非常有趣的;如果我能得到一个评论,我会:)

That being said - your only option if you want to target archaic architectures with non-0 null values is still to do manual initialization to certain members.

这就是说,如果您想要使用非0值的过时架构,那么您的惟一选项仍然是对某些成员进行手工初始化。

Thanks Thomas Padron-McCarthy! I learned something new today :)

谢谢托马斯Padron-McCarthy !我今天学到了一些新东西

#2


6  

If you don't want to use memset, you could always declare a static copy of your struct and use memcpy, which will give similar performance. This will add 4 megs to your program but is probably better than setting individual elements.

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

That said, if GCC was using memset, and it was good enough previously, I would suggest it is good enough now.

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

#3


5  

As others have said, memset is the way to go. However, don't use memset on C++ objects, particularly those with virtual methods. The sizeof( foo ) will include the table of virtual function pointers, and doing a memset on that will cause serious grief.

正如其他人所说的,memset是一条路。但是,不要在c++对象上使用memset,特别是使用虚拟方法的对象。sizeof(foo)将包含虚拟函数指针的表,并且在其上做一个memset会引起严重的悲痛。

If memset doesn't solve the problem by itself, simply do a memset and then initialize any members that should be non-zero (i.e. your non-IEEE floating point values).

如果memset本身不能解决问题,只需做一个memset,然后初始化任何非零的成员(即非ieee浮点值)。

#4


4  

Private initialization function is not ugly rather a good OO way to initialize objects (structs). I assume that your structure is not 4MB of pointers, so i would assume that the solution should be like this:

私有初始化函数并不难看,而是一种很好的对象初始化方法。我假设你的结构不是4MB的指针,所以我假设解决方案应该是这样的:

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

From other hand our code is running on more then 20 embedded operating systems and large number of different hardwares, never meet any problem with just memset of the struct.

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

#5


-2  

hmm - first of all making an init function and setting each member explicitly IS THE RIGHT THING - it,s the way constructors in OO languages work.

嗯,首先创建一个init函数并显式地设置每个成员是正确的——这是OO语言中构造函数的工作方式。

and second - does anyone know a hardware that implements non IEEE floating point numbers ? - perhaps Commodore 64 or somethig ;-)

第二,有人知道实现非IEEE浮点数的硬件吗?-可能是64名准将或什么;-)