Majora320
Majora320

Reputation: 1351

Expand string into keyword

I am writing a program which was a struct with a need to store information on what type it's holding. The data is represented inside the the struct as a pointer to void. A short example of what I mean:

#include <stdio.h>

struct foo {
    void *data;
    char *type;
};

int main() {
    struct foo bar = {{'a', 'b', 'c'}, "char"};
    printf("%s\n", (STRING_TO_TYPE(bar.type))bar.data);
    return 0;
}

I need an implementation of the STRING_TO_TYPE macro that will replace "char" with char. All of this can be evaluated at compile time for the needs of my program.
What I want to do is hold an object of any type, so using an enum or checking for string equality will not work.

Upvotes: 0

Views: 70

Answers (1)

Honza Remeš
Honza Remeš

Reputation: 1183

Short answer: it is not possible. Not your way. Macros can produce tokens (keywords, if you like), but cannot convert strings to them.

That said, if the thing you are after is really

  1. Being able to define a struct with a "type" of its void * somewhere in the code,
  2. Being able to access that type as a keyword from the struct's name,

then you will most likely end up with typeof. It is a GNU extension, so it will only work in GCC, but it works.

In the example code here, you define your struct of a certain "type" with the MYSTRUCT macro and get the type using the TYPE macro. The __COUNTER__ predefined macro prevents type redefining (each struct is its own type, see gcc -E) and three macro levels for MYSTRUCT are there for proper stringification of it.

#include <stdio.h>

#define TYPE(x) typeof(x.type)

#define MYSTRUCT(name, type) MYSTRUCT_INTER(name, type, __COUNTER__)

#define MYSTRUCT_INTER(name, type, counter) MYSTRUCT_RAW(name, type, counter)

#define MYSTRUCT_RAW(xName, xType, xCounter) \
    struct mystruct_## xCounter { \
        void * data; \
        xType type; \
    } xName

int main(void) {
    MYSTRUCT(foo, int);
    foo.data = (void *)42;

    TYPE(foo) tmp = foo.data;    /* <-- Here, tmp is an int */
    printf("%d\n", tmp);

    MYSTRUCT(bar, int*);
    bar.data = &tmp;

    TYPE(bar) tmp2 = bar.data;    /* <-- Here, tmp2 is an int* */
    printf("%p\n", tmp2);

    MYSTRUCT(baz, char*);
    baz.data = "Hello world";
    printf("%s\n", (TYPE(baz))baz.data);
    /* ^Expands to (char *)   baz.data */
}

Note that I still need to know the struct's "type" to determine printf()'s format code, but solving this was not asked.

Don't forget to compile with -std=gnu** (you need it for typeof)

Upvotes: 1

Related Questions