简体   繁体   中英

constant array in c - check if all elements are defined during compile time

i am searching for a way in C, to check during compile-time, if all elements of a constant array are set. Background is, I want to have a lookup-table with named rows and it has to be complete.

Example:

typedef enum [foo, bar, bla, max_value} rowNames;

static const uint32 LookupTable[max_value] =
{
    [foo] = 123,
    [bla] = 456, // oops, someone forgot to define the value for [bar]
}

retval = LookupTable[bar]; //this is to read out the value of the lookup table at a certain position

In this example, someone forgot to define the value for array element #1 [bar]. I want to make sure during compile time, that all values are defined, and mistakes will break the build.

Of course in reality the table will be larger and more complex, but I think this is enough to get the picture. Especially if the enums will be edited later, it is very likely that enums and table definition may get inconsistent.

regards, arnschi

Since you want it to happen at compile time, I think your only option is to create a static code analyzer to do this check, and add it to your toolchain so the verification would be done each build.

At runtime, you could use that entry at the end of the enumeration ('max_value'), and compare it against the size of your lookup table, as long as you change your table definition to be

static const uint32 LookupTable[] =
{
    /*[foo] = */123,
    /*[bla] = */456
}

This way, the array is auto-sized, and sizeof can be used to see how many entries are in it, so as soon as someone changes the enum, they will at least get a runtime error the next time they run

This can be easily done with just a few modifications do your code.

Change the array to static const uint32 LookupTable[] so that its size depends on the number of items initialized. Then initialize the array without designated initializers, just:

static const uint32 LookupTable[] =
{
  123, // foo
  456, // bla
  ...
};

Now your standard C compiler can check the integrity of the array with a compile-time assert:

_Static_assert(sizeof LookupTable / sizeof *LookupTable == max_value, 
               "LookupTable wrong number of items");

EDIT:

For strict control of the data, there's the "X macro" trick, which creates quite ugly code but centralizes all data to a single place in the source. In my example below, all data info is stored in the macro ARRAY_LIST :

#include <stdio.h>

#define ARRAY_LIST(X) \
  X(foo, 1)           \
  X(bar, 2)           \
  X(bla, 3)           \

typedef enum
{
  #define FOO_ENUM(name,val) name,
  ARRAY_LIST(FOO_ENUM)
  foo_n
} foo_t;

const int array[] =
{
  #define ARRAY_INIT(name,val) [name] = val,
  ARRAY_LIST(ARRAY_INIT)
};

_Static_assert(sizeof array / sizeof *array == foo_n, 
               "LookupTable wrong number of items");

int main (void)
{
  #define PRINT_ITEM(name,val) printf("%s: %d\n",#name, array[name]);
  ARRAY_LIST(PRINT_ITEM)
}

Pre-processor output then gives this:

typedef enum
{
  foo, bar, bla,
  foo_n
} foo_t;

const int array[] =
{
  [foo] = 1, [bar] = 2, [bla] = 3,
};

_Static_assert(sizeof array / sizeof *array == foo_n,
               "LookupTable wrong number of items");

int main (void)
{
  printf("%s: %d\n","foo", array[foo]); 
  printf("%s: %d\n","bar", array[bar]); 
  printf("%s: %d\n","bla", array[bla]);
}

And program output:

foo: 1
bar: 2
bla: 3

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM