Default parameters in C
Tags: c, macros
Published: 2021-01-08 23:27:34

#Variadic functions
*Modern* languages (like Python or Javascript) have a nice feature: they allow a function to have a variable number of arguments and, also, to define a default value for those arguments that are not specified.
This allows a more concise style of programming where some argument is specified only if it has not the "obvious" value.

C allows functions with a variable number of arguments (called *variadic functions*) through the use of a set of macros defined in the `stdarg.h` header: `va_start()`, `va_copy()`, `va_arg()` and `va_end()` to scan the list of arguments.

While they are better then nothing, I've never really liked them as they are difficult to use and have several drawbacks:
   - You have to define a way to signal the end of parameters. For example, `printf()` scans the formatting string to know how many parameters to expect while `execl()` requires you to pass `NULL` as last argument.
   - There's no type check on the parameters. This can be useful sometimes but not in general and lead to hard to find bugs.
   - The default value must be specified in the logic of the function itself, not in its definition.

I believe I'm not the only one disliking `stdarg.h` since you can find a lot of libraries whose functions require you to specify *dummy* arguments to say that you don't need to specify a value (or just want a defaut value).

For example, the standard: `strtol(s, end, base)` asks you to specify `NULL` as the second argument to signal that you're not interested in the end of the number.  I would prefer to have:

  -  `mystrtol(s,&end,16)` to get the end of the number
  -  `mystrtol(s,16)` to just convert the string
  -  `mystrtol(s)` to convert the a base 10 string

Let's see if we can do it.

C also offers *variadic macros*, i.e. macros with a variable number of arguments. Using them there are a couple of ways to avoid using `stdarg.h` and save our day. I'll present here the cleanest one I use with an example and, below, will show how this is achieved.

**Example 1**: Using `strtol()` with default values.

``` C
#include <stdio.h>
#include "vrg.h"

#define mystrtol(...)      vrg(mystrtol_, __VA_ARGS__)
#define mystrtol_1(s)      strotol(s,NULL,10)
#define mystrtol_2(s,b)    strotol(s,NULL,b)
#define mystrtol_3(s,e,b)  strotol(s,e,b)
```

Now you can just write `mystrtol("321")` to convert a 10 based string to a long integer and `mystrtol("321",16)` to consider the string as a hexadecimal number.

**Example 2**: Let's define a `greet()` function that takes two arguments (a name and a message) and prints a greetings message but allow for the second argument to be optional. If it is not specified, a default message is used.

``` C
#include <stdio.h>
#include "vrg.h"

char * msg_default = "How are you?";
#define greet(...)   vrg(greet, __VA_ARGS__)
#define greet1(n)    greetX(n, msg_default)
#define greet2(n, m) greetX(n, m)

void greetX(char *name, char *msg) {
  printf("Hello %s. %s\n", name, msg);
}

int main(int argc, char *argv[]) {
  greet("Alice", "How's your day?");
  greet("Bob"); // too lazy to think of a greeting for Bob
}
```
The code above, will produce the output:

```
Hello Alice. How's your day?
Hello Bob. How are you?
```
What we did is:
  - name the function somewhat different (`greetX()`) and write it as we would normally do, with no notion of being *variadic*.
  - define `greet()` as a variadic macro (rather than a function)
  - define a `greet1()` macro for when the greet() macro is called with only one argument.
  - define a `greet2()` macro for when the greet() macro is called with two arguments.

It works pretty well and it seems to me much easier to write (and understand) than using `stdarg.h`. Not to mention that this specific case is impossible to cover with `stdarg.h` since the behaviour of `va_arg()` is undefined if the argument does not exist!

There is the limitation that you must have at least one argument but this is true also for when you use `stdarg.h`. GCC has an extension that would allow handling 0 arguments but I prefer to stay with C99.

#Under the hood
The trick is in the `vrg.h` file included in the code above, where `vrg` serves as a mnemonic for *variadic arguments*.
I put an [extended version on Github](https://github.com/rdentato/vrg), but this is the only portion of vrg.h that is really relevant here:

``` C
#define vrg_cnt(vrg1,vrg2,vrg3,vrg4,vrg5,vrg6,vrg7,vrg8,vrgN, ...) vrgN
#define vrg_argn(...)  vrg_cnt(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define vrg_cat0(x,y)  x ## y
#define vrg_cat(x,y)   vrg_cat0(x,y)

#define vrg(vrg_f,...) vrg_cat(vrg_f, vrg_argn(__VA_ARGS__))(__VA_ARGS__)
```

The first two macros are a pretty common way to count the number of arguments passed to a C macro. It's limited to 8 arguments because, to me, having more than few arguments (and 8 is a *lot* of arguments) it's a code smell that may indicate a bigger problem in how the functions are structured. Simply say **no** to functions with too many arguments!

The other two macros are the standard way to create an identifier piecewise.

The last one puts all together and calls a different function (or macro) depending on the number of arguments.

Note that this macro is *safe* as each argument is evaluated only once.

I hope you'll find these few simple macros useful to write (and easily mantain) variadic functions that are also easy to use.

*** NOTE: the [latest version github](https://github.com/rdentato/vrg) also handles macros with 0 arguments. It's more complicated than the one presented here but gives you more flexibility.