C预处理器宏是否可能包含预处理器指令?

时间:2022-11-25 10:53:27

I would like to do the equivalent of the following:

我想做如下的对等工作:

#define print_max(TYPE) \
#  ifdef TYPE##_MAX \
     printf("%lld\n", TYPE##_MAX); \
#  endif

print_max(INT);

Now the #ifdef or any nested preprocessor directive is not allowed as far as I can see in a function macro. Any ideas?

现在,#ifdef或任何嵌套的预处理器指令都不允许在函数宏中看到。什么好主意吗?

Update: So it seems like this is not possible. Even a hack to check at runtime seems unachievable. So I think I'll go with something like:

更新:看来这是不可能的。即使是在运行时检查也不可能实现。所以我想我应该这样说:

#ifndef BLAH_MAX
#  define BLAH_MAX 0
#endif
# etc... for each type I'm interested in

#define print_max(TYPE) \
    if (TYPE##_MAX) \
       printf("%lld\n", TYPE##_MAX);

print_max(INT);
print_max(BLAH);

6 个解决方案

#1


11  

The Boost Preprocessor (which works for C as well as C++, even though Boost as a whole is a C++ library) library can help with this kind of task. Instead of using an #ifdef within a macro (which isn't permitted), it helps you include a file multiple times, with different macros defined each time, so that the file can use #ifdef.

Boost预处理器(适用于C和c++,尽管Boost作为一个整体是一个c++库)库可以帮助完成这类任务。它不允许在宏中使用#ifdef,而是帮助您多次包含一个文件,每次定义不同的宏,以便该文件可以使用#ifdef。

The following code, if saved to max.c, should do what you want for each of the words listed in the MAXES #define at the top of the file. However, it won't work if any of the _MAX values are floating point, since the preprocessor can't handle floating point.

下面的代码,如果保存到max。c,应该为文件顶部的MAXES #define中列出的每个词做您想做的事情。但是,如果任何一个_MAX值都是浮点数,那么它就不会起作用,因为预处理器不能处理浮点数。

(Boost Processor is a handy tool, but it's not exactly straightforward; you can decide whether or not this approach is an improvement over copy-and-paste.)

(Boost处理器是一种方便的工具,但并不完全简单;您可以决定这种方法是否优于复制粘贴)。

#define MAXES (SHRT)(INT)(LONG)(PATH)(DOESNT_EXIST)

#if !BOOST_PP_IS_ITERATING

/* This portion of the file (from here to #else) is the "main" file */

#include <values.h>
#include <stdio.h>
#include <boost/preprocessor.hpp>

/* Define a function print_maxes that iterates over the bottom portion of this
 * file for each word in MAXES */
#define BOOST_PP_FILENAME_1 "max.c"
#define BOOST_PP_ITERATION_LIMITS (0,BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(MAXES)))
void print_maxes(void) {
#include BOOST_PP_ITERATE()
}

int main(int argc, char *argv[])
{
    print_maxes();
}

#else

/* This portion of the file is evaluated multiple times, with
 * BOOST_PP_ITERATION() resolving to a different number every time */

/* Use BOOST_PP_ITERATION() to look up the current word in MAXES */
#define CURRENT BOOST_PP_SEQ_ELEM(BOOST_PP_ITERATION(), MAXES)
#define CURRENT_MAX BOOST_PP_CAT(CURRENT, _MAX)

#if CURRENT_MAX
printf("The max of " BOOST_PP_STRINGIZE(CURRENT) " is %lld\n", (long long) CURRENT_MAX);
#else
printf("The max of " BOOST_PP_STRINGIZE(CURRENT) " is undefined\n");
#endif

#undef CURRENT
#undef CURRENT_MAX

#endif

#2


5  

I've tried that before. The problem is that # is already reserved to stringize a macro parameter. It isn't parsed as a preprocessor token like the one in #define.

我以前试过。问题是,#已经被保留为对宏参数进行字符串化。它不会像#define中的那样被解析为一个预处理器令牌。

#3


3  

The only solution I have is cheating - produce a list of types that have an _XXX_MAX as a set of defines, and then use that. I don't know how to produce the list in automated fashion in preprocessor, so I don't try. The assumption is that the list is not too long and will not be maintained too intensively.

我唯一的解决方法是欺骗——生成一个类型列表,其中有一个_XXX_MAX作为一组定义,然后使用它。我不知道如何在预处理器中自动生成列表,所以我不尝试。假设列表不会太长,也不会太频繁地维护。

#define PRINT_MAX(type) printf("%lld\n", _TYPE##_MAX);
#define HAVE_MAX(type) _TYPE##_MAX // not sure if this works 


/* a repetitious block of code that I cannot factor out - this is the cheat */
#ifdef HAVE_MAX(INT)
#define PRINT_INT_MAX PRINT_MAX(INT)
#endif

#ifdef HAVE_MAX(LONG)
#define PRINT_LONG_MAX PRINT_MAX(LONG)
#endif
/* end of cheat */


#define print_max(type) PRINT_##TYPE##_MAX

#4


0  

I don't think it's a case of the ## operator not being allowed in an #ifdef. I tried this:

我不认为##操作符在#ifdef中不被允许。我试着这样的:

#define _print_max(TYPE) \
#ifdef TYPE \
printf("%lld\n", _TYPE); \
#endif

#define print_max(TYPE) _print_max(MAX##_TYPE)


void main() 
{
    print_max(INT)
}

and it still didn't work (it didn't like #ifdef TYPE). The problem is that #ifdef will only accept #defined symbols, not #define arguments. Those are two different things.

而且它仍然不起作用(它不喜欢#ifdef类型)。问题是#ifdef将只接受#已定义的符号,而不接受#define参数。这是两个不同的东西。

#5


0  

Unlike templates, the preprocessor is not turing-complete. An #ifdef inside a macro is not possible. Your only solution is to make sure you only call print_max on types which has a matching _MAX defined, e.g. INT_MAX. The compiler will surely tell you when they aren't.

与模板不同,预处理器不是turing-complete。在宏内的#ifdef是不可能的。您唯一的解决方案是确保只对定义了匹配_MAX的类型调用print_max,例如INT_MAX。编译器肯定会告诉你什么时候不是。

#6


0  

There's no easy way to do this. The closest you can come is to #define a large number of IFDEF macros such as:

要做到这一点并不容易。最接近的方法是#定义大量的IFDEF宏,例如:

#undef IFDEF_INT_MAX
#ifdef INT_MAX
#define IFDEF_INT_MAX(X)  X
#else
#define IFDEF_INT_MAX(X)
#endif

#undef IFDEF_BLAH_MAX
#ifdef BLAH_MAX
#define IFDEF_BLAH_MAX(X)  X
#else
#define IFDEF_BLAH_MAX(X)
#endif

     :

since you need a lot of them (and they might be useful multiple places), it makes a lot of sense to stick all these in their own header file 'ifdefs.h' which you can include whenever you need them. You can even write a script that regenerates ifdef.h from a list of 'macros of interest'

由于您需要很多这样的文件(它们可能在多个地方都很有用),所以将所有这些放在它们自己的头文件ifdefs中是很有意义的。你可以在需要的时候加上h。您甚至可以编写一个重新生成ifdef的脚本。h从一个“宏观利益”列表

Then, your code becomes

然后,代码变得

#include "ifdefs.h"
#define print_max(TYPE) \
IFDEF_##TYPE##_MAX( printf("%lld\n", TYPE##_MAX); )

print_max(INT);
print_max(BLAH);

#1


11  

The Boost Preprocessor (which works for C as well as C++, even though Boost as a whole is a C++ library) library can help with this kind of task. Instead of using an #ifdef within a macro (which isn't permitted), it helps you include a file multiple times, with different macros defined each time, so that the file can use #ifdef.

Boost预处理器(适用于C和c++,尽管Boost作为一个整体是一个c++库)库可以帮助完成这类任务。它不允许在宏中使用#ifdef,而是帮助您多次包含一个文件,每次定义不同的宏,以便该文件可以使用#ifdef。

The following code, if saved to max.c, should do what you want for each of the words listed in the MAXES #define at the top of the file. However, it won't work if any of the _MAX values are floating point, since the preprocessor can't handle floating point.

下面的代码,如果保存到max。c,应该为文件顶部的MAXES #define中列出的每个词做您想做的事情。但是,如果任何一个_MAX值都是浮点数,那么它就不会起作用,因为预处理器不能处理浮点数。

(Boost Processor is a handy tool, but it's not exactly straightforward; you can decide whether or not this approach is an improvement over copy-and-paste.)

(Boost处理器是一种方便的工具,但并不完全简单;您可以决定这种方法是否优于复制粘贴)。

#define MAXES (SHRT)(INT)(LONG)(PATH)(DOESNT_EXIST)

#if !BOOST_PP_IS_ITERATING

/* This portion of the file (from here to #else) is the "main" file */

#include <values.h>
#include <stdio.h>
#include <boost/preprocessor.hpp>

/* Define a function print_maxes that iterates over the bottom portion of this
 * file for each word in MAXES */
#define BOOST_PP_FILENAME_1 "max.c"
#define BOOST_PP_ITERATION_LIMITS (0,BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(MAXES)))
void print_maxes(void) {
#include BOOST_PP_ITERATE()
}

int main(int argc, char *argv[])
{
    print_maxes();
}

#else

/* This portion of the file is evaluated multiple times, with
 * BOOST_PP_ITERATION() resolving to a different number every time */

/* Use BOOST_PP_ITERATION() to look up the current word in MAXES */
#define CURRENT BOOST_PP_SEQ_ELEM(BOOST_PP_ITERATION(), MAXES)
#define CURRENT_MAX BOOST_PP_CAT(CURRENT, _MAX)

#if CURRENT_MAX
printf("The max of " BOOST_PP_STRINGIZE(CURRENT) " is %lld\n", (long long) CURRENT_MAX);
#else
printf("The max of " BOOST_PP_STRINGIZE(CURRENT) " is undefined\n");
#endif

#undef CURRENT
#undef CURRENT_MAX

#endif

#2


5  

I've tried that before. The problem is that # is already reserved to stringize a macro parameter. It isn't parsed as a preprocessor token like the one in #define.

我以前试过。问题是,#已经被保留为对宏参数进行字符串化。它不会像#define中的那样被解析为一个预处理器令牌。

#3


3  

The only solution I have is cheating - produce a list of types that have an _XXX_MAX as a set of defines, and then use that. I don't know how to produce the list in automated fashion in preprocessor, so I don't try. The assumption is that the list is not too long and will not be maintained too intensively.

我唯一的解决方法是欺骗——生成一个类型列表,其中有一个_XXX_MAX作为一组定义,然后使用它。我不知道如何在预处理器中自动生成列表,所以我不尝试。假设列表不会太长,也不会太频繁地维护。

#define PRINT_MAX(type) printf("%lld\n", _TYPE##_MAX);
#define HAVE_MAX(type) _TYPE##_MAX // not sure if this works 


/* a repetitious block of code that I cannot factor out - this is the cheat */
#ifdef HAVE_MAX(INT)
#define PRINT_INT_MAX PRINT_MAX(INT)
#endif

#ifdef HAVE_MAX(LONG)
#define PRINT_LONG_MAX PRINT_MAX(LONG)
#endif
/* end of cheat */


#define print_max(type) PRINT_##TYPE##_MAX

#4


0  

I don't think it's a case of the ## operator not being allowed in an #ifdef. I tried this:

我不认为##操作符在#ifdef中不被允许。我试着这样的:

#define _print_max(TYPE) \
#ifdef TYPE \
printf("%lld\n", _TYPE); \
#endif

#define print_max(TYPE) _print_max(MAX##_TYPE)


void main() 
{
    print_max(INT)
}

and it still didn't work (it didn't like #ifdef TYPE). The problem is that #ifdef will only accept #defined symbols, not #define arguments. Those are two different things.

而且它仍然不起作用(它不喜欢#ifdef类型)。问题是#ifdef将只接受#已定义的符号,而不接受#define参数。这是两个不同的东西。

#5


0  

Unlike templates, the preprocessor is not turing-complete. An #ifdef inside a macro is not possible. Your only solution is to make sure you only call print_max on types which has a matching _MAX defined, e.g. INT_MAX. The compiler will surely tell you when they aren't.

与模板不同,预处理器不是turing-complete。在宏内的#ifdef是不可能的。您唯一的解决方案是确保只对定义了匹配_MAX的类型调用print_max,例如INT_MAX。编译器肯定会告诉你什么时候不是。

#6


0  

There's no easy way to do this. The closest you can come is to #define a large number of IFDEF macros such as:

要做到这一点并不容易。最接近的方法是#定义大量的IFDEF宏,例如:

#undef IFDEF_INT_MAX
#ifdef INT_MAX
#define IFDEF_INT_MAX(X)  X
#else
#define IFDEF_INT_MAX(X)
#endif

#undef IFDEF_BLAH_MAX
#ifdef BLAH_MAX
#define IFDEF_BLAH_MAX(X)  X
#else
#define IFDEF_BLAH_MAX(X)
#endif

     :

since you need a lot of them (and they might be useful multiple places), it makes a lot of sense to stick all these in their own header file 'ifdefs.h' which you can include whenever you need them. You can even write a script that regenerates ifdef.h from a list of 'macros of interest'

由于您需要很多这样的文件(它们可能在多个地方都很有用),所以将所有这些放在它们自己的头文件ifdefs中是很有意义的。你可以在需要的时候加上h。您甚至可以编写一个重新生成ifdef的脚本。h从一个“宏观利益”列表

Then, your code becomes

然后,代码变得

#include "ifdefs.h"
#define print_max(TYPE) \
IFDEF_##TYPE##_MAX( printf("%lld\n", TYPE##_MAX); )

print_max(INT);
print_max(BLAH);