_Generic parameter beyond minimum number of arguments - c

I have found myself in strange situation trying to add some syntactic prettyness to some C code. I have triplets of numbers that are just structs.
typedef struct {int x, y, z} coord;
Now I have some functions that take 2 such structs as arguments. The simplest one counts the number of coordinates inside the 3D space defined two structs:
static inline int boxes_inside(const coord min, const coord max)
{
return (1 + max.x - min.x) * (1 + max.y - min.y) * (1 + max.z - min.z);
}
I find myself pretty regularly calling it with fixed arguments, which I find to be quite ugly
coord foo;
/* initialize foo with something */
int n = boxes_inside((coord){.x = 0, .y = 0, .z = 0}, foo);
Nevermind this example being silly, it makes more sense for more complicated functions.
I thought I would use _Generic to pass either triplets of ints, or structs.
int boxes_inside_cc(const coord min, const coord max);
int boxes_inside_ci(const coord min, const int maxx, const int maxy, const int maxz);
int boxes_inside_ic(const int minx, const int miny, const int minz, const coord max);
int boxes_inside_ii(const int minx, const int miny, const int minz, const int maxx, const int maxy, const int maxz);
#define arg1(a, ...) (a)
#define arg2(a, b ...) (b)
#define arg4(a, b, c, d, ...) (d)
#define boxes_inside(...) _Generic(arg1(__VA_ARGS__), \
coord: _Generic(arg2(__VA_ARGS__), coord: boxes_inside_cc, int: boxes_inside_ci) \
int: _Generic(arg4(__VA_ARGS__), coord: boxes_inside_ic, int: boxes_inside_ii) \
)(__VA_ARGS__)
I thought this would be fine since "the expressions of the selections that are not chosen are are never evaluated." (ref) but it turns out that since this is done after preprocessing, all macros are still expanded even in selections that are not chosen.
In particular, if I now do the following call:
coord min, max;
/* stuff */
int n = boxes_inside(min, max);
I get the problem that arg4(__VA_ARGS__) tries to expand more parameters than it actually has, even though this branch of the _Generic will never be evaluated later on.
So I then tried to expand the structs to, always have enough arguments:
#define boxes_inside_(a, b, c, d, ...) _Generic((a), \
coord: boxes_inside_ii(a, b, c, d.x, d.y, d.z), \
int: boxes_inside_ii(a, b, c, d, __VA_ARGS__) \
)
#define boxes_inside(a, ...) _Generic((a), \
coord: boxes_inside_(a.x, a.y, a.z, __VA_ARGS__) \
int: boxes_inside_(a, __VA_ARGS__) \
)
However this unsurprisingly fails with the same reason: both branches expand the other macro, in particular boxes_inside(min, max) still expands to boxes_inside_(min max) on the branch we already know won't be used.
So is there a way around this? Or are _Generic expressions basically useless if you want to test a parameter that's beyond the minimal number of parameters you might use?

Well, here goes what we discussed in the comments, even though it is not really satisfying, since it's not really an elegant solution.
First, define boxes_inside_X for every X being an acceptable number of arguments, using _Generic when necessary.
Then overload the macro by pasting the number of arguments after it (or using Boost.PP as suggested by Quentin).
/* macros that can be reused (possibly with more arguments) */
#define paste2(a, b) a ## b
#define paste(a, b) paste2(a, b)
#define get_seventh(_1, _2, _3, _4, _5, _6, this_one, ...) this_one
#define get_suffix(...) get_seventh(__VA_ARGS__, _6, _5, _4, _3, _2, _1)
/* define all variants with number of arguments suffix */
int boxes_inside_2(const coord min, const coord max);
int boxes_inside_6(const int minx, const int miny, const int minz, const int maxx, const int maxy, const int maxz);
/* make it a _Generic, if several functions have the same number of arguments */
int boxes_inside_ci(const coord min, const int maxx, const int maxy, const int maxz);
int boxes_inside_ic(const int minx, const int miny, const int minz, const coord max);
#define boxes_inside_4(a, ...) _Generic((a),\
coord: boxes_inside_ci) \
int: boxes_inside_ic) \
)(__VA_ARGS__)
/* make macro call itself with the number of arguments pasted after it */
#define boxes_inside(...) paste(boxes_inside, get_suffix(__VA_ARGS__))(__VA_ARGS__)
The upside of this approach is that you get reasonably readable error messages, for example
warning: implicit declaration of function ‘boxes_inside_3’ for the wrong number of arguments, or
expected ‘coord {aka const struct <anonymous>}’ but argument is of type ‘int’ if the types are wrong.

Related

_Generic function with several parameters

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.
There are at least two problems with your attempt:
C does not support 0-length arrays. Some implementations accept them as an extension, as it appears yours does, but as an extension, that may come with caveats, such as not working in the context you're using. But that's moot because
If the uint32_t(*)[0] alternative were selected, then you would end up with a syntactically invalid function call of the form register_read_write(a, p, r,) (note the trailing comma).
Since your macro has non-variadic arguments, you can account for that by absorbing one of them into the variadic arguments:
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);
}
Now you have a positive-length array type in every generic alternative, and it works fine. Note that the (uintptr_t) cast is required in this because the expected type of the third macro parameter is not compatible with uint32_t, and some compilers will warn about casting a 64-bit pointer to a 32-bit integer. Note well that the cast will affect only the first variadic argument, and that it anyway, neither it nor the implicit conversion of the result to type uint32_t is actually evaluated -- only the type of the expression is required.
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.

Function overloading in C using GCC - functions with mutiple arguments

In a previous question I found a way to overload functions in C99 when each function only took a single argument. See the answers in: Function overloading in C using GCC - compiler warnings for details.
Now that I've found a way to do it with single argument functions I'm wondering how this can be done for functions that take multiple arguments. I assume it will have something to do with __VA_ARGS__ and using ... but I can't seem to find anything that works or even wants to compile.
This will work for a print that takes 2 arguments:
#define print(x, y) \
__builtin_choose_expr(__builtin_types_compatible_p(typeof(x), int) && \
__builtin_types_compatible_p(typeof(y), int), print_int, \
(void)0)(x, y)
But if I also want another version that takes one argument I can't redefine it. Adding this will give me an error saying print is redefined:
#define print(x) \
__builtin_choose_expr(__builtin_types_compatible_p(typeof(x), char[]), print_string, \
(void)0)(x)
How can I overload print so it will work with 2 integers as an input or with a character array?
example usage:
print(1, 2);
print("this");
Or even better... how can I make it work with any combination of types or any number of arguments?
Also remember, since this is C99 the _Generic keyword is not available.
You can do what you want with GCC's extensions and with an overdose of preprocessor tricks. The commenters have already made their opinion clear: C is rather explicit and has a one-to-one relationship with the symbols produced. If you want function overloading and type inspection, use one of the many languages that provide them.
Baroque macro solutions tend to be toys rather than code that's suitable for production, but it's still an interesting exercise to push the envelope. Safety helemts on, though, and be aware that:
... the solution isn't portable, because the core gimmick of choosing arguments via types is already GCC specific.
... the solution is build on macros. Finding syntax errors in macros is difficult, because the error messages refer to expanded code that the user doesn't see.
... the solution pollutes the namespace with many macro names. If you really want to use this solution, prefix all your macros (except the most visible ones) consistenty as to minimize the danger of symbol collision.
That out of the way, let's implement a function put that writes its arguments to stdin according to its type:
const char *name = "Fred";
double C = 12.5;
put(1, " ", 2); // 1 2
put("Hello, I'm ", name, "!"); // Hello, I'm Fred!
put(C, " Celsius"); // 12.5 Celsius
put(C * 1.8 + 32.0, " Fahrenheit"); // 54.5 Fahrenheit
For the sake of simplicity, the solution accepts only up to three arguments of either int, const char * or double, but the maximum number of arguments is extensible.
The solution consists of these parts:
Variadic constant-type macros
Say you want to have a function that sums all arguments. The number of arguments may vary, but all arguments are of type double. If they are not of type double, they should be promoted to double.
Variadic functions aren't a good solution, because they will pass the arguments to the function per individual type. trying to sum(1, 2, 3) as double will have disastrous results.
Instead, you can use compound literals to create an array of doubles on the fly. Use the sizeof mechanism to get the length of the array. (The arguments may have side effects, because the array inside the sizeof isn't evaluated, only its size is determined.)
#define sum(...) sum_impl(sizeof((double[]){__VA_ARGS__})/ \
sizeof(double), (double[]){__VA_ARGS__})
double sum_impl(size_t n, double x[])
{
double s = 0.0;
while (n--) s += x[n];
return s;
}
This will yield 6.0 for sum(1, 2, 3) in a calculation performed on doubles.
Variant type
You want all arguments to be of the same type, but this type should be able to represent all supported types of your function. The C way to create a variant is to use a tagged union, a union inside a struct:
typedef struct var_t var_t;
struct var_t {
int type;
union {
int i;
double f;
const char *s;
} data;
};
The type could be an enumeration. I use charcter constants according the to printf formats here.
The variant of an expression is determined with a macro VAR, which is essentially the gcc specific you have posted above:
#define CHOOSE __builtin_choose_expr
#define IFTYPE(X, T) __builtin_types_compatible_p(typeof(X), T)
#define VAR(X) \
CHOOSE(IFTYPE(X, int), make_var_i, \
CHOOSE(IFTYPE(X, const char[]), make_var_s, \
CHOOSE(IFTYPE(X, const char *), make_var_s, \
CHOOSE(IFTYPE(X, double), make_var_f, \
make_var_0))))(X)
The macro invokes any of the make_var functions. These functions must be defined for each valid type:
var_t make_var_i(int X) { var_t v = {'i', {.i = X}}; return v; }
var_t make_var_s(const char *X) { var_t v = {'s', {.s = X}}; return v; }
var_t make_var_f(double X) { var_t v = {'f', {.f = X}}; return v; }
var_t make_var_0() { var_t v = {'#'}; return v; }
Incorporating the X into the type-dependent expression doesn't work, as you have already found out. Neither can you use compound literals with designated initialisers here, probably for the same reasons. (I've said that error checking with macros is hard, haven't I?)
This is the only GCC specific part; it could also be achieved with C11's _Generic.
Applying the macro to all arguments of a function
You must apply the VAR macro to all arguments of your variadic put macro. You cannot process the head of the variadic arguments until you get an empty list, because you cannot expand macros recursively, but you can use a trick that counts the arguments to the macro and then expand to a macro that takes that many arguments:
#define PUT1(_1) put_impl(1, (var_t[]){VAR(_1)})
#define PUT2(_1, _2) put_impl(2, (var_t[]){VAR(_1), VAR(_2)})
#define PUT3(_1, _2, _3) put_impl(3, (var_t[]){VAR(_1), VAR(_2), VAR(_3)})
#define SELECT_N(_1, _2, _3, N, ...) N
#define put(...) SELECT_N(__VA_ARGS__, PUT3, PUT2, PUT1)(__VA_ARGS__)
Now put takes 1, 2 or 3 arguments. If you provide more than 3, you get an obscure error message that doesn't have anything to do with not providing too many arguments.
The code above will not accept an empty argument list. With the GCC entension , ##__VA_ARGS, which will write a comma only if the variadicargument list isn't empty, you can extend this to:
#define PUT0() put_impl(0, NULL)
#define PUT1(_1) put_impl(1, (var_t[]){VAR(_1)})
#define PUT2(_1, _2) put_impl(2, (var_t[]){VAR(_1), VAR(_2)})
#define PUT3(_1, _2, _3) put_impl(3, (var_t[]){VAR(_1), VAR(_2), VAR(_3)})
#define SELECT_N(X, _1, _2, _3, N, ...) N
#define put(...) SELECT_N(X, ##__VA_ARGS__, PUT3, PUT2, PUT1,PUT0)(__VA_ARGS__)
You can extend this solution to arbitrarily many arguments if you like.
The implementation
The above macro invokes the function put_impl, which is the implementation of how to print an array of n variants. After all the tricks above, the functions is rather straightforward:
void put_impl(size_t n, const var_t var[])
{
for (size_t i = 0; i < n; i++) {
switch(var[i].type) {
case 'i': printf("%i", var[i].data.i); break;
case 'f': printf("%g", var[i].data.f); break;
case 's': printf("%s", var[i].data.s); break;
case '#': printf("[undef]"); break;
}
}
putchar('\n');
}
Putting it all together
The following program uses the method described above to print some rather silly stuff. It is not portable, but runs if compiled with gcc -std=gnu99:
#include <stdlib.h>
#include <stdio.h>
#define CHOOSE __builtin_choose_expr
#define IFTYPE(X, T) __builtin_types_compatible_p(typeof(X), T)
#define VAR(X) \
CHOOSE(IFTYPE(X, int), make_var_i, \
CHOOSE(IFTYPE(X, const char[]), make_var_s, \
CHOOSE(IFTYPE(X, const char *), make_var_s, \
CHOOSE(IFTYPE(X, double), make_var_f, \
make_var_0))))(X)
#define PUT0() put_impl(0, NULL)
#define PUT1(_1) put_impl(1, (var_t[]){VAR(_1)})
#define PUT2(_1, _2) put_impl(2, (var_t[]){VAR(_1), VAR(_2)})
#define PUT3(_1, _2, _3) put_impl(3, (var_t[]){VAR(_1), VAR(_2), VAR(_3)})
#define SELECT_N(X, _1, _2, _3, N, ...) N
#define put(...) SELECT_N(X, ##__VA_ARGS__, PUT3, PUT2, PUT1,PUT0)(__VA_ARGS__)
typedef struct var_t var_t;
struct var_t {
int type;
union {
int i;
double f;
const char *s;
} data;
};
var_t make_var_i(int X) { var_t v = {'i', {.i = X}}; return v; }
var_t make_var_s(const char *X) { var_t v = {'s', {.s = X}}; return v; }
var_t make_var_f(double X) { var_t v = {'f', {.f = X}}; return v; }
var_t make_var_0() { var_t v = {'#'}; return v; }
void put_impl(size_t n, const var_t var[])
{
for (size_t i = 0; i < n; i++) {
switch(var[i].type) {
case 'i': printf("%i", var[i].data.i); break;
case 'f': printf("%g", var[i].data.f); break;
case 's': printf("%s", var[i].data.s); break;
case '#': printf("[undef]"); break;
}
}
putchar('\n');
}
int main()
{
const char *name = "Fred";
double C = 12.5;
put(1, " ", 2);
put("Hello, I'm ", name, "!");
put();
put(C, " Celsius");
put(C * 1.8 + 32.0, " Fahrenheit");
return 0;
}
You can go crazy on the types and number of arguments you want to support, but keep inn mind that the bigger your jungle of macros gets, the harder it will be to maintain and to debug.
This solution is in no way generic, but it will get the job done for the very specific case asked in the question.
#include <stdio.h>
#define print(...) \
__builtin_choose_expr(__builtin_types_compatible_p(typeof(FIRST(__VA_ARGS__)), int), print_int, print_string)\
(__VA_ARGS__)
#define FIRST(A, ...) A
void print_int(int i, int j) {
printf("int: %d %d\n", i, j);
}
void print_string(char* s) {
printf("char*: %s\n", s);
}
int main(int argc, char* argv[]) {
print(1, 2);
print("this");
return 0;
}
If anyone can find a more generalized solution that will work consistently when new overloads are added that would be greatly appreciated.

using #ifdef for different number of function argument depending on platforms

I have a requirement that states a function should take in one new argument at the beginning of the argument list for a new platform I am working on.
so the following would be a prototype for this new platform
void foo (int newarg, const char * a, int b, int c);
where as in the previous case it was just
void foo (const char * a, int b, int c);
My concern is readability and code space . So I am thinking of using ifdefs but i am not sure if it is a good idea to use if def with in a argument list.
1)
void foo (
#ifdef __NEWPLATFORM__
int newarg,
#else
const char * a, int b, int c
#endif
);
or
#if __NEWPALTFORM__
void foo (int newarg, const char * a, int b, int c);
#else
void foo (const char * a, int b, int c);
#endif
Btw I cannot put the new argument to the end of the list which would make it a lot easier.
Which one of the two (or maybe a better solution) is better?
Thanks
Given that you are changing all the calls to foo,
just change foo to the function with more parameters, then #ifdef internal to the function for different functionality.
void foo (int newarg, const char * a, int b, int c){
#ifdef __NEWPALTFORM__
#else
#endif
}
Also worth considering whether the parameters to the function should really be a struct, in which case new parameters in the future won't be much of an issue. Not enough context in your question to say whether this is a good idea or not
but it would be something like :=
typedef struct {
int newarg;
const char* a;
int b;
int c;
} fooType;
void foo(fooType f) // either by value or by pointer depending on context
{
// #ifdefs...
}
A third option would be to conditionally define a symbol for the extra argument. You might use the #ifdef section to include other useful platform related stuff, for example:
#ifdef MY_NEW_PLATFORM
#define EXTRA_ARGS int newarg,
#define GET_EXTRA newarg
#define SET_EXTRA(val) newarg = (val)
#else
#define EXTRA_ARGS
#define GET_EXTRA 0
#define SET_EXTRA(val)
#endif
...
void foo (EXTRA_ARGS const char * a, int b, int c) {
b = GET_EXTRA + c; /* Just as example */
SET_EXTRA(b+c);
}
As you can see, the foo function has no distracting "#ifdefs", and it compiles in any platform.

C Macro expansion into multiple function calls

Is it possible to write a preprocessor macro such that would transform a variable number of arguments into successive function calls, such as
MAP(f, 1, 2, 3, ..., n)
into
f(1); f(2); f(3); ... f(n);
So far, I've got following, which seems to work:
#define MAP(f, t, ...) \
{\
t __varlist[] = {__VA_ARGS__};\
for(int i = 0; i < sizeof(__varlist) / sizeof(t); i++)\
f(__varlist[i]);\
}
Note that this macro takes a type parameter so that it can be a bit more useful.
Is there a way to do it without declaring a temporary? Or does it not matter, because the compiler is so smart that it figures out everything? I'm kind of new to C.
use boost.
note:limit size 256. BOOST_PP_LIMIT_SEQ
#include <stdio.h>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/tuple/size.hpp>
#include <boost/preprocessor/tuple/to_seq.hpp>
#define PROC(r, f, elem) f(elem);
//#define MAP(f, ...) BOOST_PP_SEQ_FOR_EACH(PROC, f, BOOST_PP_TUPLE_TO_SEQ(BOOST_PP_TUPLE_SIZE((__VA_ARGS__)),(__VA_ARGS__)))
#define MAP(f, ...) BOOST_PP_SEQ_FOR_EACH(PROC, f, BOOST_PP_TUPLE_TO_SEQ((__VA_ARGS__)))
void f(int data){
printf("%d\n", data);
}
int main(){
MAP(f, 1, 2, 3);
return 0;
}
In gcc, you can avoid the type with typeof:
#define MAP(f, a1, ...) \
{\
typeof(a1) __varlist[] = {a1, __VA_ARGS__};\
for(int i = 0; i < sizeof(__varlist) / sizeof(t); i++)\
f(__varlist[i]);\
}
Doing it without a temporary, i.e. really building N calls if there are N parameters, is possible, but rather complicated, and will be limited to some maximum (to support up to N, you'll need to define N macros).
To do this, you'll need a macro that counts its arguments (search this site), and use this number, plus concatenation, to choose one of N macros (e.g. MAP1(f, a), MAP2(f, a, b) and so on).

C default arguments

Is there a way to specify default arguments to a function in C?
Wow, everybody is such a pessimist around here. The answer is yes.
It ain't trivial: by the end, we'll have the core function, a supporting struct, a wrapper function, and a macro
around the wrapper function. In my work I have a set of macros to automate all this; once
you understand the flow it'll be easy for you to do the same.
I've written this up elsewhere, so here's a detailed external link to supplement the summary here: http://modelingwithdata.org/arch/00000022.htm
We'd like to turn
double f(int i, double x)
into a function that takes defaults (i=8, x=3.14). Define a companion struct:
typedef struct {
int i;
double x;
} f_args;
Rename your function f_base, and define a wrapper function that sets defaults and calls
the base:
double var_f(f_args in){
int i_out = in.i ? in.i : 8;
double x_out = in.x ? in.x : 3.14;
return f_base(i_out, x_out);
}
Now add a macro, using C's variadic macros. This way users don't have to know they're
actually populating a f_args struct and think they're doing the usual:
#define f(...) var_f((f_args){__VA_ARGS__});
OK, now all of the following would work:
f(3, 8); //i=3, x=8
f(.i=1, 2.3); //i=1, x=2.3
f(2); //i=2, x=3.14
f(.x=9.2); //i=8, x=9.2
Check the rules on how compound initializers set defaults for the exact rules.
One thing that won't work: f(0), because we can't distinguish between a missing value and
zero. In my experience, this is something to watch out for, but can be taken care of as
the need arises---half the time your default really is zero.
I went through the trouble of writing this up because I think named arguments and defaults
really do make coding in C easier and even more fun. And
C is awesome for being so simple and still having enough there to make all this possible.
Yes. :-) But not in a way you would expect.
int f1(int arg1, double arg2, char* name, char *opt);
int f2(int arg1, double arg2, char* name)
{
return f1(arg1, arg2, name, "Some option");
}
Unfortunately, C doesn't allow you to overload methods so you'd end up with two different functions. Still, by calling f2, you'd actually be calling f1 with a default value. This is a "Don't Repeat Yourself" solution, which helps you to avoid copying/pasting existing code.
Not really. The only way would be to write a varargs function and manually fill in default values for arguments which the caller doesn't pass.
We can create functions which use named parameters (only) for default values. This is a continuation of bk.'s answer.
#include <stdio.h>
struct range { int from; int to; int step; };
#define range(...) range((struct range){.from=1,.to=10,.step=1, __VA_ARGS__})
/* use parentheses to avoid macro subst */
void (range)(struct range r) {
for (int i = r.from; i <= r.to; i += r.step)
printf("%d ", i);
puts("");
}
int main() {
range();
range(.from=2, .to=4);
range(.step=2);
}
The C99 standard defines that later names in the initialization override previous items. We can also have some standard positional parameters as well, just change the macro and function signature accordingly. The default value parameters can only be used in named parameter style.
Program output:
1 2 3 4 5 6 7 8 9 10
2 3 4
1 3 5 7 9
OpenCV uses something like:
/* in the header file */
#ifdef __cplusplus
/* in case the compiler is a C++ compiler */
#define DEFAULT_VALUE(value) = value
#else
/* otherwise, C compiler, do nothing */
#define DEFAULT_VALUE(value)
#endif
void window_set_size(unsigned int width DEFAULT_VALUE(640),
unsigned int height DEFAULT_VALUE(400));
If the user doesn't know what he should write, this trick can be helpful:
No.
Not even the very latest C99 standard supports this.
No, that's a C++ language feature.
Probably the best way to do this (which may or may not be possible in your case depending on your situation) is to move to C++ and use it as 'a better C'. You can use C++ without using classes, templates, operator overloading or other advanced features.
This will give you a variant of C with function overloading and default parameters (and whatever other features you chose to use). You just have to be a little disciplined if you're really serious about using only a restricted subset of C++.
A lot of people will say it's a terrible idea to use C++ in this way, and they might have a point. But's it's just an opinion; I think it's valid to use features of C++ that you're comfortable with without having to buy into the whole thing. I think a significant part of the reason for the sucess of C++ is that it got used by an awful lot of programmers in it's early days in exactly this way.
Short answer: No.
Slightly longer answer: There is an old, old workaround where you pass a string that you parse for optional arguments:
int f(int arg1, double arg2, char* name, char *opt);
where opt may include "name=value" pair or something, and which you would call like
n = f(2,3.0,"foo","plot=yes save=no");
Obviously this is only occasionally useful. Generally when you want a single interface to a family of functionality.
You still find this approach in particle physics codes that are written by professional programs in c++ (like for instance ROOT). It's main advantage is that it may be extended almost indefinitely while maintaining back compatibility.
Yet another option uses structs:
struct func_opts {
int arg1;
char * arg2;
int arg3;
};
void func(int arg, struct func_opts *opts)
{
int arg1 = 0, arg3 = 0;
char *arg2 = "Default";
if(opts)
{
if(opts->arg1)
arg1 = opts->arg1;
if(opts->arg2)
arg2 = opts->arg2;
if(opts->arg3)
arg3 = opts->arg3;
}
// do stuff
}
// call with defaults
func(3, NULL);
// also call with defaults
struct func_opts opts = {0};
func(3, &opts);
// set some arguments
opts.arg3 = 3;
opts.arg2 = "Yes";
func(3, &opts);
Another trick using macros:
#include <stdio.h>
#define func(...) FUNC(__VA_ARGS__, 15, 0)
#define FUNC(a, b, ...) func(a, b)
int (func)(int a, int b)
{
return a + b;
}
int main(void)
{
printf("%d\n", func(1));
printf("%d\n", func(1, 2));
return 0;
}
If only one argument is passed, b receives the default value (in this case 15)
No.
No, but you might consider using a set of functions (or macros) to approximate using default args:
// No default args
int foo3(int a, int b, int c)
{
return ...;
}
// Default 3rd arg
int foo2(int a, int b)
{
return foo3(a, b, 0); // default c
}
// Default 2nd and 3rd args
int foo1(int a)
{
return foo3(a, 1, 0); // default b and c
}
Yes, with features of C99 you may do this. This works without defining new data structures or so and without the function having to decide at runtime how it was called, and
without any computational overhead.
For a detailed explanation see my post at
http://gustedt.wordpress.com/2010/06/03/default-arguments-for-c99/
Jens
I improved Jens Gustedt’s answer so that:
inline functions aren’t employed
defaults are computed during preprocessing
modular reuseable macros
possible to set compiler error that meaningfully matches the case of insufficient arguments for the allowed defaults
the defaults aren’t required to form the tail of the parameter list if the argument types will remain unambiguous
interopts with C11 _Generic
vary the function name by the number of arguments!
variadic.h:
#ifndef VARIADIC
#define _NARG2(_0, _1, _2, ...) _2
#define NUMARG2(...) _NARG2(__VA_ARGS__, 2, 1, 0)
#define _NARG3(_0, _1, _2, _3, ...) _3
#define NUMARG3(...) _NARG3(__VA_ARGS__, 3, 2, 1, 0)
#define _NARG4(_0, _1, _2, _3, _4, ...) _4
#define NUMARG4(...) _NARG4(__VA_ARGS__, 4, 3, 2, 1, 0)
#define _NARG5(_0, _1, _2, _3, _4, _5, ...) _5
#define NUMARG5(...) _NARG5(__VA_ARGS__, 5, 4, 3, 2, 1, 0)
#define _NARG6(_0, _1, _2, _3, _4, _5, _6, ...) _6
#define NUMARG6(...) _NARG6(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0)
#define _NARG7(_0, _1, _2, _3, _4, _5, _6, _7, ...) _7
#define NUMARG7(...) _NARG7(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0)
#define _NARG8(_0, _1, _2, _3, _4, _5, _6, _7, _8, ...) _8
#define NUMARG8(...) _NARG8(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define _NARG9(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) _9
#define NUMARG9(...) _NARG9(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define __VARIADIC(name, num_args, ...) name ## _ ## num_args (__VA_ARGS__)
#define _VARIADIC(name, num_args, ...) name (__VARIADIC(name, num_args, __VA_ARGS__))
#define VARIADIC(name, num_args, ...) _VARIADIC(name, num_args, __VA_ARGS__)
#define VARIADIC2(name, num_args, ...) __VARIADIC(name, num_args, __VA_ARGS__)
// Vary function name by number of arguments supplied
#define VARIADIC_NAME(name, num_args) name ## _ ## num_args ## _name ()
#define NVARIADIC(name, num_args, ...) _VARIADIC(VARIADIC_NAME(name, num_args), num_args, __VA_ARGS__)
#endif
Simplified usage scenario:
const uint32*
uint32_frombytes(uint32* out, const uint8* in, size_t bytes);
/*
The output buffer defaults to NULL if not provided.
*/
#include "variadic.h"
#define uint32_frombytes_2( b, c) NULL, b, c
#define uint32_frombytes_3(a, b, c) a, b, c
#define uint32_frombytes(...) VARIADIC(uint32_frombytes, NUMARG3(__VA_ARGS__), __VA_ARGS__)
And with _Generic:
const uint8*
uint16_tobytes(const uint16* in, uint8* out, size_t bytes);
const uint16*
uint16_frombytes(uint16* out, const uint8* in, size_t bytes);
const uint8*
uint32_tobytes(const uint32* in, uint8* out, size_t bytes);
const uint32*
uint32_frombytes(uint32* out, const uint8* in, size_t bytes);
/*
The output buffer defaults to NULL if not provided.
Generic function name supported on the non-uint8 type, except where said type
is unavailable because the argument for output buffer was not provided.
*/
#include "variadic.h"
#define uint16_tobytes_2(a, c) a, NULL, c
#define uint16_tobytes_3(a, b, c) a, b, c
#define uint16_tobytes(...) VARIADIC( uint16_tobytes, NUMARG3(__VA_ARGS__), __VA_ARGS__)
#define uint16_frombytes_2( b, c) NULL, b, c
#define uint16_frombytes_3(a, b, c) a, b, c
#define uint16_frombytes(...) VARIADIC(uint16_frombytes, NUMARG3(__VA_ARGS__), __VA_ARGS__)
#define uint32_tobytes_2(a, c) a, NULL, c
#define uint32_tobytes_3(a, b, c) a, b, c
#define uint32_tobytes(...) VARIADIC( uint32_tobytes, NUMARG3(__VA_ARGS__), __VA_ARGS__)
#define uint32_frombytes_2( b, c) NULL, b, c
#define uint32_frombytes_3(a, b, c) a, b, c
#define uint32_frombytes(...) VARIADIC(uint32_frombytes, NUMARG3(__VA_ARGS__), __VA_ARGS__)
#define tobytes(a, ...) _Generic((a), \
const uint16*: uint16_tobytes, \
const uint32*: uint32_tobytes) (VARIADIC2( uint32_tobytes, NUMARG3(a, __VA_ARGS__), a, __VA_ARGS__))
#define frombytes(a, ...) _Generic((a), \
uint16*: uint16_frombytes, \
uint32*: uint32_frombytes)(VARIADIC2(uint32_frombytes, NUMARG3(a, __VA_ARGS__), a, __VA_ARGS__))
And with variadic function name selection, which can't be combined with _Generic:
// winternitz() with 5 arguments is replaced with merkle_lamport() on those 5 arguments.
#define merkle_lamport_5(a, b, c, d, e) a, b, c, d, e
#define winternitz_7(a, b, c, d, e, f, g) a, b, c, d, e, f, g
#define winternitz_5_name() merkle_lamport
#define winternitz_7_name() winternitz
#define winternitz(...) NVARIADIC(winternitz, NUMARG7(__VA_ARGS__), __VA_ARGS__)
Generally no, but in gcc You may make the last parameter of funcA() optional with a macro.
In funcB() i use a special value (-1) to signal that i need the default value for the 'b' parameter.
#include <stdio.h>
int funcA( int a, int b, ... ){ return a+b; }
#define funcA( a, ... ) funcA( a, ##__VA_ARGS__, 8 )
int funcB( int a, int b ){
if( b == -1 ) b = 8;
return a+b;
}
int main(void){
printf("funcA(1,2): %i\n", funcA(1,2) );
printf("funcA(1): %i\n", funcA(1) );
printf("funcB(1, 2): %i\n", funcB(1, 2) );
printf("funcB(1,-1): %i\n", funcB(1,-1) );
}
YES
Through macros
3 Parameters:
#define my_func2(...) my_func3(__VA_ARGS__, 0.5)
#define my_func1(...) my_func2(__VA_ARGS__, 10)
#define VAR_FUNC(_1, _2, _3, NAME, ...) NAME
#define my_func(...) VAR_FUNC(__VA_ARGS__, my_func3, my_func2, my_func1)(__VA_ARGS__)
void my_func3(char a, int b, float c) // b=10, c=0.5
{
printf("a=%c; b=%d; c=%f\n", a, b, c);
}
If you want 4th argument, then an extra my_func3 needs to be added. Notice the changes in VAR_FUNC, my_func2 and my_func
4 Parameters:
#define my_func3(...) my_func4(__VA_ARGS__, "default") // <== New function added
#define my_func2(...) my_func3(__VA_ARGS__, (float)1/2)
#define my_func1(...) my_func2(__VA_ARGS__, 10)
#define VAR_FUNC(_1, _2, _3, _4, NAME, ...) NAME
#define my_func(...) VAR_FUNC(__VA_ARGS__, my_func4, my_func3, my_func2, my_func1)(__VA_ARGS__)
void my_func4(char a, int b, float c, const char* d) // b=10, c=0.5, d="default"
{
printf("a=%c; b=%d; c=%f; d=%s\n", a, b, c, d);
}
Only exception that float variables cannot be given default values (unless if it is the last argument as in the 3 parameters case), because they need period ('.'), which is not accepted within macro arguments. But can figure out a work around as seen in my_func2 macro (of 4 parameters case)
Program
int main(void)
{
my_func('a');
my_func('b', 20);
my_func('c', 200, 10.5);
my_func('d', 2000, 100.5, "hello");
return 0;
}
Output:
a=a; b=10; c=0.500000; d=default
a=b; b=20; c=0.500000; d=default
a=c; b=200; c=10.500000; d=default
a=d; b=2000; c=100.500000; d=hello
Yes you can do somthing simulair, here you have to know the different argument lists you can get but you have the same function to handle then all.
typedef enum { my_input_set1 = 0, my_input_set2, my_input_set3} INPUT_SET;
typedef struct{
INPUT_SET type;
char* text;
} input_set1;
typedef struct{
INPUT_SET type;
char* text;
int var;
} input_set2;
typedef struct{
INPUT_SET type;
int text;
} input_set3;
typedef union
{
INPUT_SET type;
input_set1 set1;
input_set2 set2;
input_set3 set3;
} MY_INPUT;
void my_func(MY_INPUT input)
{
switch(input.type)
{
case my_input_set1:
break;
case my_input_set2:
break;
case my_input_set3:
break;
default:
// unknown input
break;
}
}
you don't need to use VARARGS with just C. Here is an example.
int funcA_12(int a1, int a2) { ... }
#define funcA(a1) funcA_12(a1, 0)
This answer is very similar to the two functions method above but in this case, you're using a macro for the function name that defines the arguments.
https://github.com/cindRoberta/C/blob/master/structure/function/default_parameter.c
#include<stdio.h>
void f_impl(int a, float b) {
printf("%d %g\n", a, b);
}
#define f_impl(...) f_macro(__VA_ARGS__, 3.7)
#define f_macro(a, b, ...) f_impl(a, b)
int main(void) {
f_impl(1);
f_impl(1, 2, 3, 4);
return 0;
}
I know how to do this in a better manner.
You simply assign NULL to a parameter, so, you will have no value. Then you check if the parameter value is NULL, you change it to the default value.
void func(int x){
if(x == NULL)
x = 2;
....
}
Though, it will cause warnings. a better choice would be to assign a value that will do nothing if the parameter value is that:
void func(int x){
if(x == 1)
x = 2;
....
}
In the example above, if x is 1 the function changes it to 2;
Thanks to #user904963, EDIT:
if you have to cover all ranges of numbers, it's not hard to add another argument only to say to the function whether it would set the parameter to default or not
void func(int x, bool useDefault){
if(useDefault) //useDefault == true
x = 2;
....
}
However, remember to include stdbool.h
There's a trick I've occasionally used, which has been available since C99, using variadic macros, compound literals and designated initializers. As with any macro solution, it is cumbersome and generally not recommended other than as a last resort...
My method is built in the following way:
Wrap the actual function in a function-like, variadic macro:
void myfunc (int x, int y) // actual function
#define myfunc(...) myfunc(params) // wrapper macro
By using compound literals, copy down the parameters passed into a temporary object. This object should be a private struct corresponding directly to the function's expected parameter list. Example:
typedef struct
{
int x;
int y;
} myfunc_t;
#define PASSED_ARGS(...) (myfunc_t){__VA_ARGS__}
This means that the same type safety ("as per assignment") rules used when passing parameters to a function is also used when initializing this struct. We don't lose any type safety. Similarly, this automatically guards against providing too many arguments.
However, the above doesn't cover the case of an empty argument list. To counter this, add a dummy argument so that the initializer list is never empty:
typedef struct
{
int dummy;
int x;
int y;
} myfunc_t;
#define PASSED_ARGS(...) (myfunc_t){0,__VA_ARGS__}
Similarly, we can count the number of arguments passed, assuming that every parameter passed can get implicitly converted to int:
#define COUNT_ARGS(...) (sizeof(int[]){0,__VA_ARGS__} / sizeof(int) - 1)
We define a macro for the default arguments #define DEFAULT_ARGS (myfunc_t){0,1,2}, where 0 is the dummy and 1,2 are the default ones.
Wrapping all of this together, the outermost wrapper macro may look like:
#define myfunc(...) myfunc( MYFUNC_INIT(__VA_ARGS__).x, MYFUNC_INIT(__VA_ARGS__).y )
This assuming that the inner macro MYFUNC_INIT returns a myfunc_t struct.
The inner macro conditionally picks struct initializers based on the size of the argument list. In case the argument list is short, it fills up with default arguments.
#define MYFUNC_INIT(...) \
(myfunc_t){ 0, \
.x = COUNT_ARGS(__VA_ARGS__)==0 ? DEFAULT_ARGS.x : PASSED_ARGS(__VA_ARGS__).x, \
.y = COUNT_ARGS(__VA_ARGS__)<2 ? DEFAULT_ARGS.y : PASSED_ARGS(__VA_ARGS__).y, \
}
Full example:
#include <stdio.h>
void myfunc (int x, int y)
{
printf("x:%d y:%d\n", x, y);
}
typedef struct
{
int dummy;
int x;
int y;
} myfunc_t;
#define DEFAULT_ARGS (myfunc_t){0,1,2}
#define PASSED_ARGS(...) (myfunc_t){0,__VA_ARGS__}
#define COUNT_ARGS(...) (sizeof(int[]){0,__VA_ARGS__} / sizeof(int) - 1)
#define MYFUNC_INIT(...) \
(myfunc_t){ 0, \
.x = COUNT_ARGS(__VA_ARGS__)==0 ? DEFAULT_ARGS.x : PASSED_ARGS(__VA_ARGS__).x, \
.y = COUNT_ARGS(__VA_ARGS__)<2 ? DEFAULT_ARGS.y : PASSED_ARGS(__VA_ARGS__).y, \
}
#define myfunc(...) myfunc( MYFUNC_INIT(__VA_ARGS__).x, MYFUNC_INIT(__VA_ARGS__).y )
int main (void)
{
myfunc(3,4);
myfunc(3);
myfunc();
}
Output:
x:3 y:4
x:3 y:2
x:1 y:2
Godbolt: https://godbolt.org/z/4ns1zPW16 As you can see from the -O3 disassembly, there is zero overhead from the compound literals.
I noticed that my method reminds a bit of the current, top-voted answer. For comparison with other solutions here:
Pros:
Pure, portable standard ISO C, no dirty gcc extensions, no poorly-defined behavior.
Can handle empty argument lists.
Efficient, zero overhead, doesn't rely on function inlining getting carried out as expected.
No obscure designated initializers on the caller-side.
Cons:
Relies on every parameter being implicitly convertible to int, which often isn't the case. For example strict C does not allow implicit conversions from pointers to int - such implicit conversions is a non-conforming (but popular) compiler extension.
Default args and structs have to be generated per function. Although not covered by this answer, this could be automated with X macros. But doing so will also reduce readability even further.
Why can't we do this.
Give the optional argument a default value. In that way, the caller of the function don't necessarily need to pass the value of the argument. The argument takes the default value.
And easily that argument becomes optional for the client.
For e.g.
void foo(int a, int b = 0);
Here b is an optional argument.

Resources