Skip to content

Instantly share code, notes, and snippets.

@ELLIOTTCABLE
Created March 29, 2011 02:05
Show Gist options
  • Save ELLIOTTCABLE/891693 to your computer and use it in GitHub Desktop.
Save ELLIOTTCABLE/891693 to your computer and use it in GitHub Desktop.
Sodomizing ISO C for fun and profit.
// The upshot: (in legal, sane(?) ISO C99)
type v = Namespace__foo_bar(.first = 123, .third = "non-default value!");
/* We want a function (macro.) that appears to take “named arguments,” by preprocessing into a designated
* initializer directly at the position of the function call, post-processing.
*/
// This portion is all, effectively, a neat way to define default, named arguments.
struct _namespace__foo_bar__ARGS { int first; double second; char* third; struct widget fourth; }
void _namespace__foo_bar__INITIALZE_ARGS(struct _namespace__foo_bar__ARGS a) {
if ((int)a.first == 0) a.first = 12;
if ((int)a.second == 0) a.second = 42.0;
if ((int)a.third == 0) strcpy(&a.third , "Default!")
if ((int)a.fourth == 0) memcpy(&a.fourth , &(struct widget){ .sub = NULL }
, sizeof(struct widget));
return _namespace__foo_bar(a); }
static void _namespace__foo_bar(struct _namespace__foo_bar__ARGS a) {
// In here, we get to reference elements of `a`, our arguments struct, with default values initialized for us
return; }
// Finally, how you *actually call it*.
# define namespace__foo_bar(...) \
_namespace__foo_bar__INITIALZE_ARGS((struct _namespace__foo_bar__ARGS){ __VA_ARGS__ })//;
/* Now, how to turn this all into one easy-to-use macro replacement?
*
* Well, easy-to-use is unlikely at best. But we can do something. We’ll have to use two different primary
* macros, one for declarations and one for the actual definition. This is because we can’t cleanly take
* unlimited numbers of named pairs of type-and-name, split them apart, and then construct them into
* default-definitions or struct-member-declarations as necessary.
*
* We also need some smaller macros, utilized as the variadic arguments to the primary macros, for the
* definitions and declarations of individual types.
*/
# define VARIADIC_DECLARE(RETURNS, NAME, ...) \
struct _ ## NAME ## __ARGS { __VA_ARGS__ }; \
RETURNS _ ## NAME ## __INITIALZE_ARGS(struct _ ## NAME ## __ARGS a); \
static RETURNS _ ## NAME ## (struct _ ## NAME ## __ARGS a);
# define VARIADIC_DEFINE(RETURNS, NAME, ...) \
RETURNS _ ## NAME ## __INITIALZE_ARGS(struct _ ## NAME ## __ARGS a) { \
(__VA_ARGS__); \
return _ ## NAME ## (a); } \
static RETURNS _ ## NAME ## (struct _ ## NAME ## __ARGS a)// { … }
/* I suspect I could wrap these into a much more compact API of macros, but I’m getting tired of this exercise
* already. You grasp the basic idea, even if the definition of these macros is unnecessarily verbose. */
// “Header” arguments (used with `VARIADIC_DECLARE`.)
# define H( TYPE, NAME) TYPE NAME;
# define HD(TYPE, NAME, DEFAULT) TYPE NAME;
# define H_STR( TYPE, NAME) TYPE NAME;
# define HD_STR(TYPE, NAME, DEFAULT) TYPE NAME;
# define H_DATA( TYPE, NAME) TYPE NAME;
# define HD_DATA(TYPE, NAME, DEFAULT) TYPE NAME;
// “Implementation” arguments (used with `VARIADIC_DEFINE`.)
# define I( TYPE, NAME) (0)//;
# define ID(TYPE, NAME, DEFAULT) ( ((int)a. ## NAME == 0) ? (a. ## NAME = DEFAULT) : 0 )//;
# define I_STR( TYPE, NAME) (0)//;
# define ID_STR(TYPE, NAME, DEFAULT) ( ((int)a. ## NAME == 0) ? strcpy(&a. ## NAME , DEFAULT) : 0 )//;
# define I_DATA( TYPE, NAME) (0)//;
# define ID_DATA(TYPE, NAME, DEFAULT) ( ((int)a. ## NAME == 0) ? memcpy(&a. ## NAME , &(TYPE){ DEFAULT } , sizeof(TYPE)) : 0 )//;
// ==== THE USAGE
/* Caveat: I haven’t yet figured out a way to wrap this #define into the macro expansions above. I suspect
* there’s a way to do it involving #include, a way less ugly than the ones I’ve considered so far, but I’m not
* sure what that way is quite yet. The format doesn’t change, though, so for now, you can just copy-paste it.
*/
// something.h
VARIADIC_DECLARE(void, namespace__foo_baz, int first; double second; char* third; struct widget fourth;)
# define namespace__foo_baz(...) _namespace__foo_baz__INITIALZE_ARGS((struct _namespace__foo_baz__ARGS){ __VA_ARGS__ })//;
// something.c
VARIADIC_DEFINE(void, namespace__foo_baz, ID(int, first, 12)
, ID(double, second, 42.0)
, ID(char*, third, "Default!")
, ID(struct widget, fourth, { .sub = NULL })) {
// Implementation of `namespace__foo_baz()`.
return; }
// elsewhere.c
# include "something.h"
int main(int argc, char const **argv) {
namespace__foo_baz(.second = 5, .fourth = { .sub = &carrot });
return 0; }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment