使用C预处理器生成多个类似函数

使用C预处理器生成多个类似函数,c,function,macros,preprocessor,C,Function,Macros,Preprocessor,我想生成多个类似的函数,只替换函数中的一个单词 例如,对于以下各项: OBJECT = customer OBJECT = account 使用函数模板: void add_OBJECT_to_array(void* item_ptr, int pos) { mtx_lock(&OBJECT_array_mtx); OBJECT_array[pos] = *(OBJECT_t*)item_ptr; mtx_unlock(&OBJECT_array_mtx

我想生成多个类似的函数,只替换函数中的一个单词

例如,对于以下各项:

OBJECT = customer
OBJECT = account
使用函数模板:

void add_OBJECT_to_array(void* item_ptr, int pos)
{
    mtx_lock(&OBJECT_array_mtx);
    OBJECT_array[pos] = *(OBJECT_t*)item_ptr;
    mtx_unlock(&OBJECT_array_mtx);
    return;
}
这样我就可以打电话了

add_order_to_array(ord, 1);
add_customer_to_array(cust, 1);

这可能吗?

完全可能。您只需要了解预处理器串联运算符
##
。以下代码将生成两个函数
add\u order\u to\u array
add\u customer\u to\u array

#define GENERATE_FUNC(OBJECT) \
    void add_ ## OBJECT ## _to_array(void* item_ptr, int pos)\
    {                                                        \
        mtx_lock(&OBJECT ## _array_mtx);                     \
        OBJECT ## _array[pos] = *(OBJECT ## _t*)item_ptr;    \
        mtx_unlock(&OBJECT ## _array_mtx);                   \
        return;                                              \
    }                                                      

GENERATE_FUNC(order)
GENERATE_FUNC(customer)
预处理器输出将是(遗憾的是,它不考虑格式):

是的,有可能:

#define DECLARE_ADD_FUNCTION(__obj)                         \
    void add_##__obj##_to_array(void* item_ptr, int pos)    \
    {                                                       \
        mtx_lock(&__obj##_array_mtx);                       \
        __obj##_array[pos] = *(__obj##_t*)item_ptr;         \
        mtx_unlock(&__obj##_array_mtx);                     \
        return;                                             \
    }

DECLARE_ADD_FUNCTION(customer)
DECLARE_ADD_FUNCTION(account)
当您查看预处理器的输出时,您会得到:

gcc-E foo.c

void add_customer_to_array(void* item_ptr, int pos) { mtx_lock(&customer_array_mtx); customer_array[pos] = *(customer_t*)item_ptr; mtx_unlock(&customer_array_mtx); return; }
void add_account_to_array(void* item_ptr, int pos) { mtx_lock(&account_array_mtx); account_array[pos] = *(account_t*)item_ptr; mtx_unlock(&account_array_mtx); return; }

您甚至可以通过将函数原型更改为
add####uuu obj#u to_数组(uu obj#u t*,int pos)

保留以
开头的标识符,从而确保指针类型是正确的,因此,我会为宏参数选择一个不同的名称。-所有以下划线开头的标识符始终保留为在普通和标记名称空间中作为文件范围的标识符使用。在这种特殊情况下u obj的作用域在宏中,如果它的作用域在宏中,那么它的正确用法是u,为什么不将其命名为
obj
,而不是
\uu obj
?@AhmedMasud请注意,它是一个双下划线,所以这一段的第一个项目是适用的,而不是你所引用的。@AhmedMasud,这并不完全准确。以两个下划线或一个下划线后跟大写字母开头的标识符保留用于所有用途。以一个下划线开头,后跟一个小写字母的标识符是保留给filescope的标识符,您可以在本地作用域中重载它(这是正确的术语吗?)。我应该在头中手动写入函数原型还是也生成它们?@localhost您也可以生成它们,但使用不同的宏,例如,
GENERATE_FUNC_DECL
void add_customer_to_array(void* item_ptr, int pos) { mtx_lock(&customer_array_mtx); customer_array[pos] = *(customer_t*)item_ptr; mtx_unlock(&customer_array_mtx); return; }
void add_account_to_array(void* item_ptr, int pos) { mtx_lock(&account_array_mtx); account_array[pos] = *(account_t*)item_ptr; mtx_unlock(&account_array_mtx); return; }