Question

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:

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

The new GCC (3.4.x) was doing this

   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!

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 )

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' 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.

Was it helpful?

Solution

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

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...

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.

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

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.

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

OTHER TIPS

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.

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

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.

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).

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:

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.

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.

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top