How can a macro define a valid global name based on the type passed to it?

守給你的承諾、 提交于 2021-02-10 04:36:05

问题


I believe the title is self-explanatory, but here's an example to illustrate what I'm trying to accomplish:

#define PASTE2(_0, _1)  _0 ## _1

#define DEFINE_OPS_FOR_TYPE(TYPE)                   \
    int PASTE2(do_something_with_, TYPE)(void) {    \
        /* do_something_with_<TYPE> */              \
    }

Everything works fine for char, int, and single-worded types, but when it comes to unsigned types, or others that have multiple keywords, using token pasting (a ## b) does not generate a valid name due to the whitespace (e.g.: do_something_with_foo bar).

The easiest solution I could think of is to change the DEFINE_OPS_FOR_TYPE macro to take a valid name as the 2nd parameter. For example:

#define DEFINE_OPS_FOR_TYPE(TYPE, NAME_FOR_TYPE)            \
    int PASTE2(do_something_with_, NAME_FOR_TYPE)(void) {   \
        /* do_something_with_<NAME_FOR_TYPE> */             \
    }

This works as expected, but I'm curious about other possible solutions, even if they're overly complex. I thought of using _Generic, but I fail to see how it would help in defining a name.

Can you think of another solution?


回答1:


On the level of declaration or definition of the symbols that you want to do there is not much way out of typedefing things to a unique identifier for the type in question. _Generic or equivalent replacements kick in too late to be useful for the preprocessor.

But there is only a finite number of standard types that pose such a problem. So you can easily come up with a convention for typedeffing these.

Where _Generic can help is on the usage side of your such defined symbols. Here you can then do something like

_Generic((X),
  unsigned long: do_something_with_ulong,
  unsigned char: do_something with_uchar,
  ...
)(X)

In P99 I follow this scheme, and you would find a lot of support macros for it already in place.




回答2:


I ended up using a macro with an empty argument. Example:

#define STR2(x)             # x
#define STR(x)              STR2(x)
#define PASTE3(_1,_2,_3)    _1 ## _2 ## _3
#define FOO(_1,_2,_3)       PASTE3(_1, _2, _3)

printf("%s\n", STR(FOO(int,,)));
printf("%s\n", STR(FOO(unsigned, int,)));
printf("%s\n", STR(FOO(unsigned, long, long)));

As you can see here, the output is:

int
unsignedint
unsignedlonglong

I don't remember whether using empty macro arguments is well defined according to the standard, but I can tell you that Clang 3.1 doesn't emit any warnings for -std=c11 with -pedantic.

Here's some code if you want to try:

#include <stdio.h>
#include <limits.h>

#define PASTE4(_1,_2,_3,_4) _1 ## _2 ## _3 ## _4

#define DEFINE_OPS_FOR_TYPE1(T1)        DEFINE_OPS_FOR_TYPE2(T1,)
#define DEFINE_OPS_FOR_TYPE2(T1, T2)    DEFINE_OPS_FOR_TYPE3(T1,T2,)
#define DEFINE_OPS_FOR_TYPE3(T1, T2, T3)                                    \
    int PASTE4(write_,T1,T2,T3)(FILE *file, void *data) {                   \
        T1 T2 T3 foo;                                                       \
        int written = fprintf(file, fmt_specifier(foo), *((T1 T2 T3 *)data));\
        return written > 0 ? 0 : -1;                                        \
    }

#define fmt_specifier(x)                \
    _Generic((x),                       \
        int: "%i",                      \
        unsigned int: "%u",             \
        unsigned long long: "%llu",     \
        default: NULL                   \
    )

DEFINE_OPS_FOR_TYPE1(int)
DEFINE_OPS_FOR_TYPE2(unsigned, int)
DEFINE_OPS_FOR_TYPE3(unsigned, long, long)

int main() {
    int var_int = INT_MAX;
    write_int(stdout, &var_int);
    printf("\n");
    unsigned int var_uint = UINT_MAX;
    write_unsignedint(stdout, &var_uint);
    printf("\n");
    unsigned long long var_ullong = ULLONG_MAX;
    write_unsignedlonglong(stdout, &var_ullong);
    printf("\n");
    return 0
}


来源:https://stackoverflow.com/questions/14137291/how-can-a-macro-define-a-valid-global-name-based-on-the-type-passed-to-it

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!