0

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.

13
  • Don't think you can use the preprocessor for string comparison. Commented Mar 25, 2016 at 23:36
  • 3
    C is statically typed. You should use a dynamically typed language for that. Or use a different approach. Note that you shoud not use void * where avoidable. For your application, a union would be the better approach. And use an enum for the type. Commented Mar 25, 2016 at 23:37
  • @FiddlingBits: At least not in a macro. Commented Mar 25, 2016 at 23:37
  • 1
    This looks like an XY-problem. Provide more information what you actually want to accomplish and we might give better help. Commented Mar 25, 2016 at 23:39
  • 1
    If you store three chars behind a void* with no other information as to interpret the pointer as char*, how do you know later on in your program it's 3? (and not 1 or 1000) Commented Mar 25, 2016 at 23:39

1 Answer 1

1

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)

Sign up to request clarification or add additional context in comments.

1 Comment

Because you can make anonymous struct types, you don't need all three macros. You can just do: #define MYSTRUCT(name, _type) struct { void *data; _type type; } name;.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.