Static initialization of an array of structs in C

10,912

Solution 1

The only solution that jumps to mind would be to initialize it with a simple loop somewhere

Which is the only possibility within the language, I'm afraid. In C, you either initialize each element explicitly, initialize to all zeros or don't initialize.

However, you can sidestep the issue by using 0 for the purpose that your -1 currently serves.

Solution 2

The C99 standard added all sorts of useful ways to initialize structures, but did not provide a repeat operator (which Fortran has had since forever - but maybe that was why it wasn't added).

If you are using a sufficiently recent version of GCC and you can afford to use a non-portable extension, then GCC provides an extension. In the GCC 8.1.0 manual (§6.27 Designated Initializers), it says:

To initialize a range of elements to the same value, write ‘[first ... last] = value’. This is a GNU extension. For example,

int widths[] = { [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 };

If the value in it has side-effects, the side-effects will happen only once, not for each initialized field by the range initializer.

So, using this in your example:

struct memPermissions memPermissions[numBoxes] =
{
    [0..numBoxes-1] = {-1, -1},    // GCC extension
};

I wish this were in the C Standard; it would be so helpful!


Without using that or other similar compiler-specific mechanisms, your only choice is a loop. For a complex initializer with many fields, not all the same value, you can probably use:

#include <string.h>
#include "memperm.h"  // Header declaring your types and variables

static int initialized = 0;
// -2 so the initialization isn't uniform and memset() is not an option
static const struct memPermissions initPermissions = { -1, -2 };
struct memPermissions memPermissions[numBoxes];

void initialize_permissions(void)
{
    if (initialized == 0)
    {
        for (int i = 0; i < numBoxes; i++)
            memmove(&memPermissions[i], &initPermissions, sizeof(initPermissions));
        initialized = 1;
    }
}

You can also use memcpy() here - there is no danger of the two variables overlapping.

Now you just need to ensure that initialize_permissions() is called before the array is used - preferably just once. There may be compiler-specific mechanisms to allow that, too.

You could use a local variable in the initialize_permissions() function in place of the initialized static constant variable - just be sure your compiler doesn't initialize it every time the function is called.

If you have a C99 compiler, you can use a compound literal in place of the constant:

void initialize_permissions(void)
{
    if (initialized == 0)
    {
        for (int i = 0; i < numBoxes; i++)
            memmove(&memPermissions[i],&(struct memPermissions){ -1, -2 },
                    sizeof(memPermissions[0]));
        initialized = 1;
    }
}

Solution 3

You can write an external program that is passed the number of items that you want. This program should be called by your Makefile or equivalent. The program will write an include file for you with the required number of -1 values as well as the #define.

Solution 4

If you have the standard library available, you can use memset combined with sizeof(struct memPermissions) * numBoxes to fill your array with any uniform byte value. Since -1 is 0xFFFFFFFF on many platforms, this might work for you.

Share:
10,912
JoshVarty
Author by

JoshVarty

My blog.

Updated on June 11, 2022

Comments

  • JoshVarty
    JoshVarty almost 2 years

    I have a question regarding the initialization of an array of structs in C. Googling showed me that a lot of people have had very similar questions, but they weren't quite identical.

    Essentially, I have a global array of structs of type "memPermissions" shown below. This array needs all the "address" and "ownerId" fields to be initialized to -1 upon program execution.

    typedef struct memPermissions {
        int address;
        int ownerId;
    } *test;
    

    The problem is the array is sized using a #define, so I can't simply go:

    #define numBoxes 5
    
    struct memPermissions memPermissions[numBoxes] = {
    {-1, -1},
    ...
    {-1, -1}
    };
    

    I tried:

    struct memPermissions memPermissions[numBoxes] = {-1, -1};
    

    But naturally this only initialized the first element. (The rest were set to 0). The only solution that jumps to mind would be to initialize it with a simple loop somewhere, but because of the nature of where this code will run, I'm really hoping that's not my only option.

    Is there any way to initialize all the elements of this array of structs without a loop?

    Cheers, -Josh

  • mctylr
    mctylr over 12 years
    Close, but you need to consider the size of the int, and need to write -1 to both of them.
  • Jarek
    Jarek over 12 years
    This really seems like overkill
  • JoshVarty
    JoshVarty over 12 years
    The issue was best solved in my case by using a third field within the structure initialized to 0. Unfortunately, I couldn't use either of the two existing fields because 0 was a possible value for them to be set to later in program execution. However, since your answer put me on track to solve this, I accepted it. Thanks!