C 预处理器宏:检查 token 是否已声明
这是针对 C 预处理器专家的:
我如何声明一个带有一些标识符列表的 enum
,然后在 switch 语句中检查列表中是否包含标识符?
我需要的示例:
typedef enum { e1, e2, e3, e4, e5, e6 } e;
e x;
switch (x) {
#if DECLARED_IN_ENUM (e1)
case e1 : ...
#endif
/* etc. */
}
我考虑使用 Boost 序列并将其扩展为枚举中的逗号分隔列表,但是稍后如何检查该序列是否包含某个标记?
编辑:我能用Boost做的是:
#define e1 e1
#define e2 e2
#define e3 e3
#define e4 e4
#define e5 e5
#define e6 e6
#define E (e1)(e2)(e3)(e4)(e5)(e6)
typedef enum { BOOST_PP_SEQ_ENUM(E) } e;
e x;
switch (x) {
#if defined (e1)
case e1 : ...
#endif
/* etc. */
}
这不是很漂亮,我更喜欢这样的东西:
#define E (e1)(e2)(e3)(e4)(e5)(e6)
typedef enum { BOOST_PP_SEQ_ENUM(E) } e;
e x;
switch (x) {
#if BOOST_PP_SEQ_CONTAINS (e1,E)
case e1 : ...
#endif
/* etc. */
}
但是如何实现BOOST_PP_SEQ_CONTAINS
?
This is for the C preprocessor experts:
How can I declare an enum
with a list of some identifiers and later during the switch-statement check if an identifier was included in the list?
Example of what I need:
typedef enum { e1, e2, e3, e4, e5, e6 } e;
e x;
switch (x) {
#if DECLARED_IN_ENUM (e1)
case e1 : ...
#endif
/* etc. */
}
I thought of using a Boost sequence and expanding it into a comma separated list in the enum, but how can I check later if the sequence contains a certain token?
EDIT: What I was able to do with Boost is:
#define e1 e1
#define e2 e2
#define e3 e3
#define e4 e4
#define e5 e5
#define e6 e6
#define E (e1)(e2)(e3)(e4)(e5)(e6)
typedef enum { BOOST_PP_SEQ_ENUM(E) } e;
e x;
switch (x) {
#if defined (e1)
case e1 : ...
#endif
/* etc. */
}
That is not very beautiful, and I would prefer something like:
#define E (e1)(e2)(e3)(e4)(e5)(e6)
typedef enum { BOOST_PP_SEQ_ENUM(E) } e;
e x;
switch (x) {
#if BOOST_PP_SEQ_CONTAINS (e1,E)
case e1 : ...
#endif
/* etc. */
}
but how could BOOST_PP_SEQ_CONTAINS
be implemented?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
你不能。 C 预处理器并不“理解”C 编程语言,它只是将其标记化。它不知道“enum”的实际含义。编译器会处理这个问题。
如果您想在预处理器中测试某些内容,则必须提供预处理器宏以供其使用。
编辑:抱歉,错过了您打算使用 Boost.Preprocessor。我不知道一旦您在枚举的定义中涉及了 Boost 的某些内容,这是否可以提供必要的宏。
You can't. The C preprocessor doesn't "understand" the C programming language, it just tokenizes it. It doesn't know what "enum" actually means. The compiler handles that.
If you want to test something in the preprocessor, then you'll have to provide preprocessor macros for it to use.
Edit: sorry, missed that you were intending to use Boost.Preprocessor. I don't know whether that can provide the necessary macros, or not, once you've involved something from Boost in the definition of your enum.
我认为
BOOST_PP_SEQ_CONTAINS
无法实现。它要求您能够比较两个预处理标记序列,但您无法做到这一点。然而,如果你稍微重新安排你的逻辑,你可以得到更接近你想要的东西。首先,我们需要几个与
BOOST_PP_SEQ_FOR_EACH
一起使用的辅助宏:我们可以定义枚举器列表和枚举,就像您在原始问题中所做的那样:
如您所见,我星期五离开了从名单上删除是因为周五没有人真正工作。让我们考虑一个返回一些描述星期几的文本的函数作为示例。
我们没有测试列表中是否包含枚举数,而是使用宏定义每个值的情况:
然后,我们使用
WORKDAY_ENUMERATORS
并将枚举数与WORKDAY_CASE_
前缀:如果某一天未包含在
WORKDAY_ENUMERATORS
列表中,则不会为其生成案例。因为我们在使用预处理器时应该礼貌,所以我们取消定义我们使用的宏:
我认为这有点丑陋,但这是获得几乎您正在寻求的结果的一种方法。
I don't think
BOOST_PP_SEQ_CONTAINS
can be implemented. It would require you to be able to compare two sequences of preprocessing tokens, which you can't do.However, if you rearrange your logic a bit, you can get something closer to what you want. First, we need a couple of helper macros for use with
BOOST_PP_SEQ_FOR_EACH
:We can define the list of enumerators and the enumeration just as you have in the original question:
As you can see, I've left Friday off of the list because no one actually does work on Friday. Let's consider as an example a function that returns some text describing the day of the week.
Instead of testing whether an enumerator was included in the list, we define the cases for each of the values using macros:
We then generate the correct case statements for the list by using the
WORKDAY_ENUMERATORS
and concatenating the enumerators with theWORKDAY_CASE_
prefix:If a day was not included in the
WORKDAY_ENUMERATORS
list, no case will be generated for it.Because we should be polite when we use the preprocessor, we then undefine the macros we used:
I think this is kind of ugly, but it's one way to get almost the results you are seeking.
只是不要使用
enum
。它没有任何有用的目的。使用#define
声明所有常量,并使用#ifdef
。Just don't use
enum
. It serves no useful purpose. Declare all your constants with#define
, and use#ifdef
.一种方法是拥有一个很大的 #define 或“.h”文件,涵盖您所有的工作日(.h 文件的优点是您不需要用反斜杠结束所有点赞)并包含它们的所有相关信息在宏中。然后 #define 生成器宏来做某事,调用大宏(或 #include 标头),#undef 生成器宏并定义它做其他事情,再次调用大宏,等等。在这种情况下,一种变体生成器宏会生成类似“case ENUM_foo: func_foo(); break;”的内容。然后,您可以为适当的 func_* 函数编写所有适当的代码,并且将根据需要调用它们。
One approach is to have a great big #define or ".h" file which covers all your weekdays (the .h file has the advantage that you don't need to end all likes with backslash) and includes all the relevant information for them in macros. Then #define the generator macro to do something, invoke the big macro (or #include the header), #undef the generator macro and define it to do something else, invoke the big macro again, etc. In this scenario, one variation of the generator macro would generate something like "case ENUM_foo: func_foo(); break;". You could then write all the appropriate code for the appropriate func_* functions and they would be called as appropriate.