【问题标题】:Generate multiple similar functions with C preprocessor使用 C 预处理器生成多个类似的函数
【发布时间】:2023-03-08 04:09:01
【问题描述】:

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

例如,对于以下各项:

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

这可能吗?

【问题讨论】:

    标签: c function macros preprocessor


    【解决方案1】:

    完全有可能。您只需要了解预处理器串联运算符##。下面的代码会生成两个函数add_order_to_arrayadd_customer_to_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)
    

    预处理器输出将是(不幸的是它不尊重格式):

    void add_order_to_array(void* item_ptr, int pos) { mtx_lock(&order_array_mtx); order_array[pos] = *(order_t*)item_ptr; mtx_unlock(&order_array_mtx); return; }
    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; }
    

    【讨论】:

    • 我应该在标题中手动编写函数原型还是应该生成它们?
    • @localhost 你也可以生成它们,但是使用不同的宏,例如GENERATE_FUNC_DECL
    【解决方案2】:

    是的,有可能:

    #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_##__obj##_to_array(__obj##_t *, int pos)来确保指针类型是正确的类型

    【讨论】:

    • __ 开头的标识符是保留的,所以我会为宏参数选择一个不同的名称。
    • — 所有以下划线开头的标识符始终保留用作普通和标记名称空间中具有文件范围的标识符。在这种特殊情况下,__obj 是在宏范围内的,并且是 __ 的正确使用
    • 如果它的范围是宏,为什么不直接将其命名为obj 而不是__obj
    • @AhmedMasud 请注意,它是双下划线,因此该段落的 first 项目符号适用,而不是您引用的项目符号。
    • @AhmedMasud 这并不完全准确。以两个下划线或一个下划线后跟一个大写字母开头的标识符保留供所有使用。以单个下划线后跟小写字母开头的标识符是为文件范围保留的标识符,您可以在本地范围内重载(这是正确的术语吗?)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-18
    • 2014-11-27
    • 1970-01-01
    • 1970-01-01
    • 2010-11-18
    • 1970-01-01
    相关资源
    最近更新 更多