Reputation: 322
I have some code need to set an array to some (dynamic) values. Depending on some factors the contents of the array should have different sources. This can not be done automatically and needs to be written out by hand.
array[0] = x;
array[1] = y;
array[2] = z;
....
..
I want this to somewhat automatic, so my first approach was this:
void set_array(char *array, int_num args, ...){
va_list valist;
va_start(valist, num_args);
for(int i=0; i < num_args; i++)
array[i] = va_arg(valist, char);
va_end(valist);
}
Where calling set_array(array, x, y, z)
will result in array[0] = x
, array[1] = y
etc..
However speed is of the essence, so I wanted to get rid of the function call and the dynamic memory allocation.
My second approach is this:
#define SET1(i, A, B) A[i] = B;
#define SET2(i, A, B, C) A[i] = B; SET1(i+1, A, C)
#define SET3(i, A, B, C, D) A[i] = B; SET2(i+1, A, C, D)
#define SET4(i, A, B, C, D, E) A[i] = B; SET3(i+1, A, C, D, E)
#define SET5(i, A, B, C, D, E, F) A[i] = B; SET4(i+1, A, C, D, E, F)
#define SET6(i, A, B, C, D, E, F, G) A[i] = B; SET5(i+1, A, C, D, E, F, G)
#define SET7(i, A, B, C, D, E, F, G, I) A[i] = B; SET6(i+1, A, C, D, E, F, G, I)
#define GET_MACRO(_1,_2,_3,_4,_5,_6,_7,_8,_9,NAME,...) NAME
#define SET(...) GET_MACRO(0, __VA_ARGS__, SET7, SET6, SET5, SET4, SET3, SET2, SET1)(0, __VA_ARGS__)
Where calling SET(array, x, y, z)
will result in array[0] = x
, array[1] = y
etc..
This method results in faster code but requires me to write a macro for each number of arguments. Is there a method to use macros but circumvent this?
Upvotes: 1
Views: 280
Reputation: 107779
If I understand correctly, you want a way to assign to an array with the syntactic convenience that's available for array initialization…
array = {x, y, z}
but it's an assignment that takes place at runtime, and not an initialization.
You can do it by assigning to a temporary array and copying immediately. Any halfway decent compiler will optimize the copy away.
{
int tmp = {x, y, z};
memcpy(array, tmp, sizeof(tmp));
}
You can pack this into a macro. Leave out the static_assert
in C99 (it's a new feature in C11).
#include <assert.h>
#include <stdlib.h>
#include <string.h>
int array[42];
size_t used_size;
#define SET_ARRAY(...) \
do { \
int const SET_ARRAY_tmp[] = {__VA_ARGS__}; \
static_assert(sizeof(SET_ARRAY_tmp) <= sizeof(array), \
"too many values in assignment to array"); \
memcpy(array, SET_ARRAY_tmp, sizeof(SET_ARRAY_tmp)); \
used_size = sizeof(SET_ARRAY_tmp) / sizeof(SET_ARRAY_tmp[0]); \
} while (0)
void f(int fourth) {
SET_ARRAY(123, 456, 789, fourth);
}
Note that the number of elements has to be known at compile time. If you only know the number of elements to copy at runtime, you're going to need a different approach, although since you have to pull the elements from somewhere it would likely be just a memcpy
.
Upvotes: 3