Here's an amusing trick that I was just discussing with Mark Wooding on IRC.
Did you know you can define functions with optional and/or named arguments in C99? It's not even completely horrible!
The main limitation is there must be at least one non-optional
argument, and you need to compile with -std=c99
-Wno-override-init
.
(I originally wrote that this code needs C11, but Miod Vallat pointed out it works fine in C99)
The pattern works like this, using a function called repeat()
as an
example.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Define the argument list as a structure. The dummy argument
// at the start allows you to call the function with either
// positional or named arguments.
struct repeat_args {
void *dummy;
char *str;
int n;
char *sep;
};
// Define a wrapper macro that sets the default values and
// hides away the rubric.
#define repeat(...) \
repeat((struct repeat_args){ \
.n = 1, .sep = " ", \
.dummy = NULL, __VA_ARGS__ })
// Finally, define the function,
// but remember to suppress macro expansion!
char *(repeat)(struct repeat_args a) {
if(a.n < 1)
return(NULL);
char *r = malloc((a.n - 1) * strlen(a.sep) +
a.n * strlen(a.str) + 1);
if(r == NULL)
return(NULL);
strcpy(r, a.str);
while(a.n-- > 1) { // accidentally quadratic
strcat(r, a.sep);
strcat(r, a.str);
}
return(r);
}
int main(void) {
// Invoke it like this
printf("%s\n", repeat(.str = "ho", .n = 3));
// Or equivalently
printf("%s\n", repeat("ho", 3, " "));
}