I declared a function with the following signature (implementation is simplified):
#include <stdio.h>
struct test_s{
int a, b;
};
void foo(struct test_s **out, size_t *szs, size_t arr_len){
for(size_t i = 0; i < arr_len; i++){
for(size_t j = 0; j < szs[i]; j++){
struct test_s ts = out[i][j];
printf("a = %d; b = %d\n", ts.a, ts.b);
}
}
}
In case a caller uses arrays to be adjusted to pointers it can be called as follows:
int main(void){
struct test_s a1[] = {{0, 1}, {2, 3}, {4, 5}};
struct test_s a2[] = {{4, 6}};
foo((struct test_s *[]){a1, a2},
(size_t[]){sizeof a1 / sizeof(struct test_s), sizeof a2 / sizeof(struct test_s)},
2);
}
As can be seen the function call looks complicated, error-prone and hard to read.
When it comes to using 3 arguments things get worse:
int main(void){
struct test_s a1[] = {{0, 1}, {2, 3}, {4, 5}};
struct test_s a2[] = {{4, 6}};
struct test_s a3[] = {{2, 3}, {4, 5}};
foo((struct test_s *[]){a1, a2, a3},
(size_t[]){sizeof a1 / sizeof(struct test_s), sizeof a2 / sizeof(struct test_s), sizeof a3 / sizeof(struct test_s)},
3);
}
So it would be perfect to implement it as macro when it comes to arrays. It is pretty straightforward to implement it as follows:
#define FOO_ARR_2(a1, a2) \
do{ \
foo((struct test_s *[]){a1, a2}, \
(size_t[]){sizeof a1 / sizeof(struct test_s), sizeof a2 / sizeof(struct test_s)}, \
2);\
} while(0)
I see 2 problems with such a macro:
FOO_ARR_3
, FOO_ARR_4
, etc...struct test_s[]
QUESTION: Would it be possible to implement it as a variadic macro function like #define FOO_ARR(...)
?
Instead of complicating things even more by wrapping the complicate initialisation into a complicated (if even possible) variadic macro, just declare the function in question as a variadic one itself.
This might look like this:
#include <stdio.h>
#include <stdarg.h>
/* expects: number-of-arrays followed by
number-of-arrays tuples {arrays-size, pointer to array's 1st element} */
struct test_s{
int a, b;
};
void foo(size_t arr_len, ...)
{
va_list vl;
va_start(vl, arr_len);
for (size_t i = 0; i < arr_len; ++i)
{
size_t s = va_arg(vl, size_t);
struct test_s * p = va_arg(vl, struct test_s *);
for (size_t j = 0; j < s; ++j)
{
struct test_s ts = p[j];
printf("a = %d; b = %d\n", ts.a, ts.b);
}
}
va_end(vl);
}
Use it like this:
struct test_s{
int a, b;
};
void foo(size_t, ...);
int main(void)
{
/* using two arrays: */
{
struct test_s a1[] = {{0, 1}, {2, 3}, {4, 5}};
struct test_s a2[] = {{4, 6}};
foo(2,
sizeof a1 / sizeof *a1, a1,
sizeof a2 / sizeof *a2, a2
);
}
/* using three arrays: */
{
struct test_s a1[] = {{0, 1}, {2, 3}, {4, 5}};
struct test_s a2[] = {{4, 6}};
struct test_s a3[] = {{2, 3}, {4, 5}};
foo(3,
sizeof a1 / sizeof *a1, a1,
sizeof a2 / sizeof *a2, a2,
sizeof a3 / sizeof *a3, a3
);
}
}