使用 C 预处理器给出数组值

use C pre-processor to give an array values

我有一些代码需要将数组设置为一些(动态)值。根据某些因素,数组的内容应该有不同的来源。这不能自动完成,需要手动写出来。

array[0] = x;
array[1] = y;
array[2] = z;
....
..

我希望它有点自动,所以我的第一个方法是:

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);
}

调用 set_array(array, x, y, z) 将导致 array[0] = xarray[1] = y 等。

但是速度很重要,所以我想摆脱函数调用和动态内存分配。

我的第二种方法是:

#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__)

调用 SET(array, x, y, z) 将导致 array[0] = xarray[1] = y 等。

此方法会产生更快的代码,但需要我为每个参数数量编写一个宏。有没有使用宏的方法来规避这个?

如果我没理解错的话,你想要一种方法来分配给一个数组,它具有可用于数组初始化的语法便利…

array = {x, y, z}

但这是在运行时发生的赋值,而不是初始化。

您可以通过分配给临时数组并立即复制来完成。任何半途而废的编译器都会优化副本。

{
    int tmp = {x, y, z};
    memcpy(array, tmp, sizeof(tmp));
}

你可以把它打包成一个宏。省略 C99 中的 static_assert(这是 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);
}

请注意,元素的数量必须在编译时已知。如果您只知道在运行时要复制的元素数量,您将需要一种不同的方法,尽管由于您必须从 某处 中提取元素,因此它可能只是一个 memcpy.