Hanks
Hanks

Reputation: 379

Create a specific macro with typeof in C

To simplify the question, if I have two structs like the following:

typedef struct test1_s {
    uint16_t value1;
    uint16_t b;
} test1_t;

typedef struct test2_s {
    uint32_t value1;
    uint32_t c;
} test2_t;

And I want a macro to work like this:

value = GET(x, value1);

but for different type of x, different process will be done for x->value1.

What I'm thinking of is that:

#define GET_test1_t_value1(x) x->value1 + 1
#define GET_test2_t_value1(x) x->value1 + 2
#define GET(x, field) GET_##typeof(x)##_##field(x)

But looks like the typeof can not work like this....

Is there any way to achieve that? It needs to be done in pure C. Thanks!

Upvotes: 0

Views: 435

Answers (2)

BLUEPIXY
BLUEPIXY

Reputation: 40145

,sample in C11

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

typedef struct test1_s {
    uint16_t value1;
    uint16_t b;
} test1_t;

typedef struct test2_s {
    uint32_t value1;
    uint32_t c;
} test2_t;


#define GET(x, field) (x->field + _Generic(*x, test1_t: 1, test2_t:2))

int main(){
    uint32_t value;
    test1_t *x = &(test1_t){1,2};
    test2_t *y = &(test2_t){3,4};

    value = GET(x, value1);
    printf("%" PRIu32 "\n", value);//2
    value = GET(y, value1);
    printf("%" PRIu32 "\n", value);//5
    return 0;
}

Upvotes: 0

Keith Thompson
Keith Thompson

Reputation: 263237

typeof is non-standard (it's an extension provided by gcc, and perhaps by some other compilers). And it doesn't expand to a string, so as you've already discovered you can't use in a macro definition like the one you're trying to do.

C11 added a new _Generic keyword that permits something like what you want. It's used in a new kind of expression called a generic selection.

An example from the C standard:

#define cbrt(X) _Generic((X), \
                        long double: cbrtl, \
                        default: cbrt, \
                        float: cbrtf \
                        )(X)

(The default association permits the use of cbrt for integer types, which will be implicitly converted to double.)

See section 6.5.1.1 of the N1570 draft of the 2011 ISO C standard.

Of course you can use this only if your compiler supports it. gcc first added support for _Generic in release 4.9, which came out just a few days ago.

Upvotes: 2

Related Questions