I am using several similar functions and want to make one overloadable.
The basic function takes 3 parameters, and its successive expansions take 4 or more.
#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__))
declarations
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);
and it works fine but i can't add a basic function with 3 parameters:
void register_read_write(access_t action, parameter_t parameter, uint16_t *reg_value)
i try:
#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__))
but:
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},
following the blow....
I'm developing my generic functions and ran into another problem.
#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__))
I don't know why, but it doesn't detect pointer type correctly.
i change
#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__))
and still failed :-(
Please give me some suggestions.
regards
P.S. I am looking for a good tutorial on how the "_Generic" functionality works.
Consider such implementation:
#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);
}
I.e. detect number of arguments with macros, and detect types with _Generic
. One tool for one job.
Revisiting the answer, I think it would be nice to have it in one place instead of multiple. The following counts the arguments and overloads on the pointer of an array with a size depending on the size of register and argument count. In this code instead of offsetting of sizeof(*r)
you could also just do _Generic(r, uint8_t*: 10, uint16_t*: 20)
.
#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 ARGCOUNT_N(_0,_1,_2,N,...) N
#define ARGCOUNT(...) ARGCOUNT_N(__VA_OPT__(,) __VA_ARGS__,2,1,0)
#define register_read_write(a, p, r, ...) \
_Generic((char(*)[sizeof(*r) * 10 + ARGCOUNT(__VA_ARGS__)])0 \
, char(*)[sizeof( uint8_t) * 10 + 0]: func_u8_0 \
, char(*)[sizeof( uint8_t) * 10 + 1]: func_u8_1 \
, char(*)[sizeof( uint8_t) * 10 + 2]: func_u8_2 \
, char(*)[sizeof(uint16_t) * 10 + 0]: func_u16_0 \
, char(*)[sizeof(uint16_t) * 10 + 1]: func_u16_1 \
, char(*)[sizeof(uint16_t) * 10 + 2]: func_u16_2 \
)(a, p, r __VA_OPT__(,) __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);
}