Function overloading in C using GCC - functions with mutiple arguments - c

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.

Related

(C) macro that contains 2 args in macro doesn't compile, but it works well in function. I want to know why. Thanks

Yesterday I tried to optimize my code using macro, but it doesn't compile in some sentences. For simplification, I writed codes below to describe what I want to work out:
#define MACRO(x, y) ((x) + (y))
#define X 2,3
int fun(x, y)
{
return x+y;
}
int main(void)
{
int res;
res = fun(X); //ok
res = MACRO(X); //**error:macro "MACRO" requires 2 arguments, but only 1 given**
printf("%d\n", res);
return 0;
}
I used to believe that macros simply replace words so it's no problem to do this, but now I think I was wrong. :(
More accurately: I was tring to do something like:
//global.h
#define MACRO(brief, num) fun(__LINE__, brief, num)
//test.c
#include <global.h>
#define X "brief",3
void fun(int line_num, char* brief, int num)
{
printf("%d, %s,%d\n", line_num, brief, num); //do something
}
int main(void)
{
fun(__LINE__, X); //ok
MACRO("brief",3); //ok
MACRO(X); //error: macro "MACRO" requires 2 arguments, but only 1 given
return 0;
}
So I need to use this type of macro to reduce args.
I searched everywhere yesterday but nothing was found, I hope I could receive answers here. Thanks a lot. :)
(My English is not very good, I wish I had a clear description of my problem.)
You can use the variable arguments facility of the preprocessor, as in the following example (available on IdeOne):
#include <stdio.h>
#define MACRO(...) MACRO_IMPLEMENTATION(__VA_ARGS__)
#define MACRO_IMPLEMENTATION(x,y) ((x)+(y))
#define X 2,3
int main (void) {
printf ("MACRO (X) = %d\n", MACRO (X));
printf ("MACRO (2,3) = %d\n", MACRO (2,3));
return 0;
}
The output is
MACRO (X) = 5
MACRO (2,3) = 5
The definition of MACRO takes a variable number or arguments, which are bound to __VA_ARGS__ (see section 6.10.3 in the standard). The definition of MACRO calls MACRO_IMPLEMENTATION which now sees two arguments either because MACRO was called with two or because it was called with an argument which expands to a list of two arguments.

Use of pasting operator `##` with types in C

Is it possible to define a macro for the C preprocessor which takes an array as argument and expands to <type of array elements>_string? For example if x in an array of integers the macro invoked with argument x should expand to int_string.
I tried with
#define TypePaste(array) typeof(array[0])##_string
but it expands to )_string.
Even using multiple levels of indirection for the ## operand the macro doesn't expand correctly.
That's not possible. At the translation phase (the preprocessing phase) where macros are expanded and tokens are concatenated, the compiler (at this point, the preprocessor) does not yet have the notion of a type and thus cannot possibly generate types.
It is not all that clear what problem you are trying to solve, but given your comment:
the macro should expand to the name of an existing function. I'd like to define a function <type>_string for every existing type and then use the macro to select the right function according to the type of the array given.
Then you could use the C11 _Generic keyword:
#include <stdio.h>
void int_string (size_t size, int array[size])
{
printf("I am %s, do stuff here.\n", __func__);
}
void float_string (size_t size, float array[size])
{
printf("I am %s, do stuff here.\n", __func__);
}
#define TypePaste(array) \
_Generic( array, \
int: int_string, \
float: float_string ) \
(sizeof(array)/sizeof(*array), array) // function parameters
int main()
{
int i_arr[5];
float f_arr[3];
TypePaste(i_arr);
TypePaste(f_arr);
}
Output:
I am int_string, do stuff here.
I am float_string, do stuff here.
Note: this assumes that the passed parameter is a local/file scope allocated array. If passing a pointer, there's no type safety and the program will fail.
C11's _Generic type selection is the "proper" way to do what you want. There are other, platform dependent solutions, tough.
If you are using gcc – you don't say so eplicitly, but you use gcc's extension typeof already – you can use gcc's statement expresions and nested functions to create a comparison function for qsort on the spot:
double a[5] = {8.4, 8.1, 9.3, 12.2, 5.2};
qsort(a, 5, sizeof(*a), ({
int cmp(const void *p, const void *q) {
const typeof(a[0]) *pp = p;
const typeof(a[0]) *qq = q;
return (*pp < *qq) ? -1 : (*pp > *qq);
}
cmp;
}));
This creates a function and returns its address. (The last statement of a compound expression is its value. The scope of the local variables is the statement expression, but a nested function is not created on the stack so its safe to return a pointer to that function.)
For primitive types, where you want to sort according to the comparison operators < and >, you can turn that into a macro:
#define COMPARE(ARRAY)({ \
int cmp(const void *p, const void *q) { \
const typeof(ARRAY[0]) *pp = p; \
const typeof(ARRAY[0]) *qq = q; \
return (*pp < *qq) ? -1 : (*pp > *qq); \
} \
cmp; \
})
qsort(a, 5, sizeof(*a), COMPARE(a));
or even:
#define SORT(ARRAY, N) \
qsort(ARRAY, N, sizeof(*ARRAY), COMPARE(ARRAY))
SORT(a, 5);
That's not Standard C, so if you need compatibility between platforms, this is out of the question.

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).

Can I print #defines given their values in C?

I have
#define ADD 5
#define SUB 6
Can I print ADD and SUB given their values 5 and 6?
No.
The names of the defined symbols are removed by the preprocessor, so the compiler never sees them.
If these names are important at runtime, they need to be encoded in something more persistent than just preprocessor symbol names. Perhaps a table with strings and integers:
#define DEFINE_OP(n) { #n, n }
static const struct {
const char *name;
int value;
} operators[] = {
DEFINE_OP(ADD),
DEFINE_OP(SUB),
};
This uses the stringifying preprocessor operator # to avoid repetitions.
With the above, you can trivially write look-up code:
const char * op_to_name(int op)
{
size_t i;
for(i = 0; i < sizeof operators / sizeof *operators; ++i)
if(operators[i].value == op)
return operators[i].name;
return NULL;
}
you can do something like
printf("%d", ADD);
and it will print 5
The thing you have to remember about defines is:
Defines are substituted into the source code by the preprocessor before it is compiled so all instances of ADD in your code are substituted by 5. After the preprocessor the printf looks like this:
printf("%d", 5);
So to answer your question:
No you can't do it like that.
Yes, but not in via some reverse lookup mechanism wherein the value 5 is somehow symbolic in regards to the string "ADD". The symbols defined via a #define are tectually replaced by the pre-processor. You can however keep it simple:
const char *get_name(int value) {
switch(value) {
case ADD:
return "ADD";
case SUB:
return "SUB";
default:
return "WHATEVER";
}
}
#include <stdio.h>
int main() {
printf("%s = %d\n", get_name(ADD), ADD);
printf("%s = %d", get_name(SUB), SUB);
}
With modern C, since C99, this is even much simpler than unwind's answer by using designated initializers and compound literals
#define DEFINE_OP(n) [n] = #n
#define OPNAMES ((char const*const opNames[]){ \
DEFINE_OPT(ADD), \
DEFINE_OPT(SUB), \
})
inline
char const* getOp(unsigned op) {
size_t const maxOp = sizeof OPNAMES/ sizeof *OPNAMES;
if (op >= maxOp || !OPNAMES[op]) return "<unknown operator>";
else return OPNAMES[op];
}
Any modern compiler should be able then to expand calls as getOp(ADD) at compile time.

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