_具有多个参数的通用函数
_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”功能如何工作的好教程。
您的尝试至少存在两个问题:
C 不支持长度为 0 的数组。一些实现接受它们作为扩展,就像你的一样,但作为扩展,可能会附带一些警告,例如不能在你正在使用的上下文中工作。但这没有意义,因为
如果选择了 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
检测类型。一件工作一件工具。
我正在使用几个类似的函数,并且想使一个可重载。
基本函数需要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”功能如何工作的好教程。
您的尝试至少存在两个问题:
C 不支持长度为 0 的数组。一些实现接受它们作为扩展,就像你的一样,但作为扩展,可能会附带一些警告,例如不能在你正在使用的上下文中工作。但这没有意义,因为
如果选择了
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
检测类型。一件工作一件工具。