3

I'm using an array of functions pointers, and I'd like to use it directly with their associated event IDs. Problem is, event IDs start from 0x10 to 0x1C, and from 0x90 to 0xA5.

I don't want to write ten NULL elems at the beginning, is it possible somehow to declare like this :

int (*tab[256])(uint8_t *data, int *datalen) = {
   NULL[10],
   fun1,
   [...],
   funx,
   NULL[116],
...
};

For now, I don't see a satisfying solution, that's why I'm asking

3
  • 1
    Are you looking for strictly-standard C or are extensions ok? Commented Nov 7, 2023 at 17:04
  • Hi welcome to the forum. Personally I prefer to define a structure type that has a function pointer and event Id element, then define an array of the structure type. All elements will initially be null. You can then search for event id in the array. Usual trade off, speed verses memory. Commented Nov 7, 2023 at 17:06
  • A better tradeoff of speed versus memory is to use a conditional statement to map the IDs to the range 0x00 to 0x25. Then you only need 3 NULL entries in the array instead of 221, and no designated initializers are necessary. On processors with conditional move instructions, the code will be branchless, so almost no time is wasted. Code example: array_index = (id < 0x20) ? (id - 0x10) : (id - 0x80). Commented Nov 7, 2023 at 18:49

2 Answers 2

5

You can do this in standard C using designated initializers:

int (*tab[256])(uint8_t *data, int *datalen) = {
   [0x10] = fun_a_1,
   fun_a_2,
   fun_a_3,
   ...
   fun_a_n,
   [0x90] = fun_b_1,
   fun_b_2,
   fun_b_3,
   ...
};

The syntax [n] = x sets the n'th element of the array to the given value. We use this to set the first of the non-NULL elements in a group. Subsequent initializers are then set in order after the the given object, so you don't need to explicitly specify the index for each one. We can also take advantage of the fact that array elements not explicitly initialized are set to NULL.

So in the above example, element 0x10 is explicitly set to the first function pointer. The next object in the initializer list then applies to element 0x11, the next to 0x12 and so forth.

While some compilers may support a range of initializers as an extension, i.e. [ 0 ... 9 ], the above does not depend on such extensions and is conforming to the C standard.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you, and as I was wondering, all not specified elements are initialized to 0, as said in the documentation
2

If you are using C99 or later (or are using GCC as your compiler and compile with GNU extensions enabled), you can express this using Designated Initializers. For example:

int (*tab[256])(uint8_t *data, int *datalen) = {
   [0 ... 9] = NULL, /* optional, requires GNU extension */
   [0x10] = fun1,
   [0x11] = fun2,    /* additional designators are optional after the first in sequence */
   /* ... */         /* only the first designator '[0x10] =' is required. */
   [0x1C] = funN,    
                     
   [0x90] = funa,
   /* ... */
   [0xA5] = funz,   /* again, '[0xA5] =' is optional when listing values in sequence. */
};

Entries without a initializer will be implicitly initialized to 0.

2 Comments

[0 ... 9] = NULL, part is redundant
@tstanisl correct, it's annotated as such in the answer, and mentioned in the last sentence.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.