Sjoerd Vermeulen
Sjoerd Vermeulen

Reputation: 57

Passing a union as one of two arguments in a macro

I'm trying to define a generic/macro function that sets a property of a union i've defined. I've worked with macros before, but never tried to pass multiple arguments. In this case I got a union which represents a variable (Nothing really interesting) and I want to have a single set function that allows me to set the correct property of the union's instance without specifying the datatype. This is my code:

// represents a variable
union Var {
  float f;
  char *s;
  bool b;
  // 'f' 's' or 'b'
  char type;
};

// setter
void set_int(union Var *var, int newval) { var->f = (float)newval; var->type = 'f'; }
void set_float(union Var *var, float newval) { var->f = newval; var->type = 'f'; }
void set_char(union Var *var, char newval) { var->s = (char[2]){newval, 0}; var->type = 's'; }
void set_string(union Var *var, char *newval) { var->s = newval; var->type = 's'; }
void set_bool(union Var *var, bool newval) { var->b = newval; var->type = 'b'; }
#define set(VAR, X) \
  _Generic((X), \
    int: set_int(union Var, X), \
    float: set_float(union Var), \
    char: set_char(union Var), \
    char *: set_string(union Var), \
    bool: set_bool(union Var))(X)

int main(void) {
    union Var myvar;

    // myvar.f = 1.5; myvar.type = 'f'; works, but i want to do this instead:
    set(&myvar, 1.5);

    return 0;
}

the output that i'm getting:

var.c: In function ‘main’:
var.c:92:18: error: expected expression before ‘union’
     int: set_int(union Var, X), \
                  ^~~~~
var.c:117:5: note: in expansion of macro ‘set’
     set(&myvar, 1.5);
     ^~~
var.c:92:10: error: too few arguments to function ‘set_int’
     int: set_int(union Var, X), \
          ^~~~~~~
var.c:117:5: note: in expansion of macro ‘set’
     set(&myvar, 1.5);
     ^~~
var.c:85:6: note: declared here
 void set_int(union Var *var, int newval) { var->f = newval; var->type = 'f'; }
      ^~~~~~~

I'm getting desparate, so any help would be appreciated a lot!

PS: I'm not great at C at all, so don't burn me down if I'm making a stupid mistake. :)

Upvotes: 3

Views: 229

Answers (1)

dbush
dbush

Reputation: 223739

Your macro is expanding to pass a type name for the first parameter to the function, which is not valid syntax. You want instead to pass whatever the VAR parameter is:

#define set(VAR, X) \
  _Generic((X), \
    int: set_int, \
    float: set_float, \
    double: set_float, \
    char: set_char, \
    char *: set_string, \
    bool: set_bool)((VAR), (X))

Upvotes: 3

Related Questions