Using preprocessor ## to call a function dynamically

Viewed 90

I have a function called create_car. I am trying to use a preprocessor macro so that I can call the function by doing Create(car). Here is what I have thus far:

#define ObjName(X)  _Generic((X), struct Person: "person", struct Car: "car")
#define NewObj(X)   create_ ## ObjName(X)

struct Car* create_car(void) 
{
   // do something here
}
struct Car {
    char* make;
    char* model;
    int year;
    void (*print)(struct Car*);
};

int main(void)
{
    struct Car *car = NewObj(struct Car);
}

But when trying that I get the following error:

gen.c:5:21: warning: implicit declaration of function ‘create_ObjName’; did you mean ‘create_car’? [-Wimplicit-function-declaration]
 #define NewObj(X)   create_ ## ObjName(X)
                     ^
gen.c:40:5: note: in expansion of macro ‘NewObj’
     NewObj(struct Car);
     ^~~~~~
gen.c:40:12: error: expected expression before ‘struct’
     NewObj(struct Car);
            ^
gen.c:5:40: note: in definition of macro ‘NewObj’
 #define NewObj(X)   create_ ## ObjName(X)

What does the issue seem above with how I'm trying to create the object from the macro?

What I'm looking the code to become after preprocessed/compiled is:

int main(void)
{
    struct Car *car = create_car();
}
1 Answers

You cannot do it this way. The C preprocessor does not know about _Generic. It will treat is a normal name, a potential candidate for further expansion.

However, you could use _Generic in definition of NewObj macro. The issue is the argument of NewObj(X) is not a value but a type. However you can bypass it by dispatching over a NULL pointer to X to find a proper constructor function.

#define NewObj(X)  _Generic(((X*)0), struct Person*: create_person(), struct Car*: create_car())

The simplified resulting code would be:

#include <stdio.h>

struct Car;
struct Person;

struct Car* create_car(void) {
    puts("Create a car");
    return NULL;
}

struct Person* create_person(void) {
    puts("Create a person");
    return NULL;
}

#define NewObj(X)  _Generic(((X*)0), struct Person*: create_person(), struct Car*: create_car())

int main(void)
{
    struct Car *car = NewObj(struct Car);
    struct Person *person = NewObj(struct Person);
    return 0;
}

Prints as expected:

Create a car
Create a person

Anyway, I suggest calling create_car()/create_person() directly as it is more readable.

Related