_具有多个参数的通用函数

_Generic function with several parameters

我正在使用几个类似的函数,并且想使一个可重载。
基本函数需要3个参数,其连续扩展需要4个或更多。

#define register_read_write(action, parameter, reg_value, ...) 
        _Generic(&(uint32_t[]){__VA_ARGS__}, 
        uint32_t(*)[2]: register_read_write_with_limits,
        uint32_t(*)[1]: register_read_write_with_upper_limit)
            ((action), (parameter), (reg_value), (__VA_ARGS__))

声明

void register_read_write_with_limits(access_t action, parameter_t parameter, uint16_t *reg_value, 
                                     uint32_t value_min, uint32_t value_max);

void register_read_write_with_upper_limit(access_t action, parameter_t parameter, uint16_t *reg_value, 
                                     uint32_t value_max);

它工作正常,但我无法添加具有 3 个参数的基本函数:

void register_read_write(access_t action, parameter_t parameter, uint16_t *reg_value)

我试试:

#define register_read_write(action, parameter, reg_value, ...) 
        _Generic(&(uint32_t[]){__VA_ARGS__}, 
        uint32_t(*)[2]: register_read_write_with_limits,
        uint32_t(*)[1]: register_read_write_with_upper_limit,
        uint32_t(*)[0]: register_read_write)
            ((action), (parameter), (reg_value), (__VA_ARGS__))

但是:

error: '_Generic' selector of type 'uint32_t ()[0]' {aka 'long unsigned int ()[0]'} is not compatible with any association #define register_read_write(action, parameter, reg_value, ...) _Generic(&(uint32_t[]){VA_ARGS},

打击之后....

我正在开发我的泛型函数并 运行 解决另一个问题。

#define FIRST_ARG(value, ...) (value)

#define generic_uint8_read_write(action, parameter, ...) 
        _Generic(&(uint32_t[]){(uintptr_t)__VA_ARGS__},
        uint32_t(*)[1]: register_uint8_read_write)(action, parameter, __VA_ARGS__)

#define generic_uint16_read_write(action, parameter, ...) _Generic(&(uint32_t[]){(uintptr_t)__VA_ARGS__},                
         uint32_t(*)[2]: register_read_write_with_limits,
        uint32_t(*)[1]: register_read_write_with_upper_limit,
        uint32_t(*)[0]: register_read_write)(action, parameter, __VA_ARGS__)

#define generic_read_write(action, parameter, ...)   
        _Generic(FIRST_ARG(__VA_ARGS__),
        uint8_t*: generic_uint8_read_write(action, parameter, __VA_ARGS__),
        uint16_t* : generic_uint16_read_write(action, parameter, __VA_ARGS__))

我不知道为什么,但它没有正确检测指针类型。

我改

#define generic_read_write(action, parameter, value, ...)   
        _Generic((value),
        uint8_t*: generic_uint8_read_write(action, parameter, value, __VA_ARGS__),
        uint16_t* : generic_uint16_read_write(action, parameter, value, __VA_ARGS__))

仍然失败:-(

请给我一些建议。

问候
P.S。我正在寻找有关“_Generic”功能如何工作的好教程。

您的尝试至少存在两个问题:

  1. C 不支持长度为 0 的数组。一些实现接受它们作为扩展,就像你的一样,但作为扩展,可能会附带一些警告,例如不能在你正在使用的上下文中工作。但这没有意义,因为

  2. 如果选择了 uint32_t(*)[0] 选项,那么您将以 register_read_write(a, p, r,) 形式的语法无效函数调用结束(注意尾随逗号)。

由于您的宏具有非可变参数,您可以通过将其中之一吸收到可变参数中来解决这一问题:

void register_read_write(action_t action, parameter_t parameter, uint16_t *reg_value);

void register_read_write_with_limits(action_t action, parameter_t parameter, uint16_t *reg_value, 
                                     uint32_t value_min, uint32_t value_max);

void register_read_write_with_upper_limit(action_t action, parameter_t parameter, uint16_t *reg_value, 
                                     uint32_t value_max);

#define register_read_write(a, p, ...)  \
        _Generic(&(uint32_t[]){(uintptr_t) __VA_ARGS__},  \
        uint32_t(*)[3]: register_read_write_with_limits, \
        uint32_t(*)[2]: register_read_write_with_upper_limit, \
        uint32_t(*)[1]: register_read_write) \
            ((a), (p), __VA_ARGS__)

void bar() {
    int a = 0;
    int b = 0;
    uint16_t u16 =  0;
    uint32_t min = 0;
    uint32_t max = 0;

    register_read_write(a, b, &u16, min, max);
    register_read_write(a, b, &u16, max);
    register_read_write(a, b, &u16);
}

现在您在每个通用替代方案中都有一个正长度数组类型,并且它工作正常。请注意,这里需要进行 (uintptr_t) 强制转换,因为第三个宏参数的预期类型与 uint32_t 不兼容,一些编译器会警告将 64 位指针强制转换为 32 位整数.请注意,强制转换只会影响第一个可变参数,而且无论如何,它和结果到类型 uint32_t 的隐式转换都不会被实际评估——只需要表达式的类型。

考虑这样的实现:

#include <stdint.h>
#include <stdio.h>
#define BODY  { printf("%s\n", __func__); }
void func_u8_0(int action, int param, uint8_t *reg) BODY
void func_u8_1(int action, int param, uint8_t *reg, int min) BODY
void func_u8_2(int action, int param, uint8_t *reg, int min, int max) BODY
void func_u16_0(int action, int param, uint16_t *reg) BODY
void func_u16_1(int action, int param, uint16_t *reg, int min) BODY
void func_u16_2(int action, int param, uint16_t *reg, int min, int max) BODY

#define register_read_write_1(a, p, r) \
    _Generic((r), \
        uint8_t*: func_u8_0, \
        uint16_t*: func_u16_0 \
    )
#define register_read_write_2(a, p, r, min) \
    _Generic((r), \
        uint8_t*: func_u8_1, \
        uint16_t*: func_u16_1 \
    )
#define register_read_write_3(a, p, r, min, max) \
    _Generic((r), \
        uint8_t*: func_u8_2, \
        uint16_t*: func_u16_2 \
    )
#define register_read_write_N(_3,_2,_1,N,...) register_read_write_##N
#define register_read_write(a, p, ...) \
    register_read_write_N(__VA_ARGS__,3,2,1)(a, p, __VA_ARGS__)(a, p, __VA_ARGS__)

int main() {
    register_read_write(1, 1, (uint8_t*)0);
    register_read_write(1, 1, (uint8_t*)0, 1);
    register_read_write(1, 1, (uint8_t*)0, 1, 1);
    register_read_write(1, 1, (uint16_t*)0);
    register_read_write(1, 1, (uint16_t*)0, 1);
    register_read_write(1, 1, (uint16_t*)0, 1, 1);
}

即使用宏检测参数数量,使用 _Generic 检测类型。一件工作一件工具。