Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compile-time lookup table in C (C11)

Tags:

arrays

c

c11

I was wondering if C had functionality within the language or compiler (gcc) to allow me to turn my const intialized array into a compile-time lookup table of const structs. Here is a remodel of my situation:

typedef struct Entry {
    bool alive;
    float a, b, c;
    double d, e, f;
} Entry;

Now, I have a declaration for the array:

extern const int entryCount; // Assume this is equal to an enum value.
extern const Entry entries[entryCount];

As stated, the position in the array are relative to an enum constant that is characteristic of the data put into the entry structure. Assume that entryCount is initialized to the number of entries in the enumeration. Here is where my question is, when I initialize this array like so:

const int entryCount = ENTRY_COUNT;
const Entry entries[entryCount] = {
    { false, 0.1f, 0.2f, 0.0f, 1.0, 1.0, -1.0 },
    ...
};

Are they created at compile-time and create no overhead in runtime? Or is it allocated in memory at runtime? Because the values will never change. How can I achieve this in C?

like image 934
Steven Floyd Avatar asked Oct 21 '22 15:10

Steven Floyd


1 Answers

You can achieve what you want if all of the components that you need to define your array are compile time constants in the sense of the C standard. The only thing that isn't of what you have given is entryCount. It really must be an enum constant.

Then you'd have to put that array as a global (file scope) array. If you want to include the same array through an include file (.h) in different .c files (so-called compilation units) you'd have to declare it static, such that multiple definitions wouldn't conflict when you link the program.

enum { entryCount = ENTRY_COUNT };
static const Entry entries[entryCount] = {
    { false, 0.1f, 0.2f, 0.0f, 1.0, 1.0, -1.0 },
    ...
};

static here means that this creates a variable that has a lifetime that spans the whole execution of the program, but that no external symbol for this variable is generated. This is necessary if you #include the same definition of a variable into several .c files.

This has no runtime overhead and access to an entry such as entries[4].d should nowadays be optimized away by a good optimizing compiler.

This has only one drawback, in that it duplicates the generation of the array in all units, even if it is not needed, there. One way to avoid that would be a macro that expands to a compound literal like this

#define ENTRIES (const Entry [entryCount]){        \
    { false, 0.1f, 0.2f, 0.0f, 1.0, 1.0, -1.0 },   \
    ...                                            \
}

The const than leaves leeway to the compiler to allocate that array only once (if any) and will avoid an extra copy in compilation units that don't use that feature at all.

like image 180
Jens Gustedt Avatar answered Oct 30 '22 12:10

Jens Gustedt