Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Static initialization of an array of structs in C

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

like image 373
JoshVarty Avatar asked Nov 20 '11 21:11

JoshVarty


2 Answers

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;
    }
}
like image 107
Jonathan Leffler Avatar answered Nov 01 '22 10:11

Jonathan Leffler


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.

like image 23
Zan Lynx Avatar answered Nov 01 '22 11:11

Zan Lynx