Skip to content

Instantly share code, notes, and snippets.

@mkmik
Last active August 29, 2015 14:07
Show Gist options
  • Save mkmik/05e027f75460251d992a to your computer and use it in GitHub Desktop.
Save mkmik/05e027f75460251d992a to your computer and use it in GitHub Desktop.
/*
* Quick and dirty optional option struct via function overload via preprocessor trick.
*
* requires C99 and gnu extension, for ", ## __VA_ARGS"
*/
#include <stdio.h>
///////// Magic library
// expand to prefix + suffix where suffix is either s0 or s0 depending whether the vararg list is the same length as
// args or 1 item longer.
// usage: #define function M_DISPATCH(function, _one, _two, M_FIXED_ARGS(arg0, arg1), ## __VA_ARGS__)
#define M_DISPATCH(prefix, s0, s1, args, ...) M_CONCAT(prefix, VA_SUFFIX(s0, s1, 0, ## __VA_ARGS__))(args, ## __VA_ARGS__)
// call it to declare the list of the fixed arguments of the function
#define M_FIXED_ARGS(...) __VA_ARGS__
// returns either a or b depending of whether it's called by 1 or 2 vararg arguments
// note: not zero, you have pass a dummy first argument for it to work if you want to
// discriminate between 0 or 1 parameters.
#define __BAD _ARG_LIST_TOO_LONG_RTFM
#define VA_SUFFIX(a,b,...) VA_SUFFIX_IMPL(__VA_ARGS__, __BAD, __BAD, __BAD, b, a)
#define VA_SUFFIX_IMPL(_1,_2,_3,_4,_5, N,...) N
// double indirection needed to concatenate two macro expansions
#define M_CONCAT(x,y) M_PASTER(x,y)
#define M_PASTER(x,y) x ## y
////////// REAL CODE
// ---- ns_send
typedef struct {
int deadline;
int n_headers;
} ns_send_opts_t;
// define a dispatcher that will invoke ns_send_legacy if invoked with only two parameters
// and ns_send_opts if invoked with three parameters.
#define ns_send(addr, body, ...) M_DISPATCH(ns_send, _legacy, _opts, M_FIXED_ARGS(addr, body), ## __VA_ARGS__)
void ns_send_opts(char* addr, char* body, ns_send_opts_t opts) {
printf("sending %s to %s, deadline: %d, headers: %d\n", addr, body, opts.deadline, opts.n_headers);
}
void ns_send_legacy(char* addr, char* body) {
ns_send_opts(addr, body, (ns_send_opts_t){0});
}
////////// USAGE
int main() {
ns_send("x", "addr");
ns_send_opts_t opts = {.deadline = 1};
ns_send("x", "addr", opts);
// not super nice, but parseable error message indicating that there are too many arguments
// ns_send("x", "addr", opts, x);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment