简体   繁体   English

将枚举转换为c的宏

[英]MACRO that converts enum to type in c

I'm trying this for over a week with no success. 我已经尝试了一个多星期,但没有成功。

I'm creating a logger interface between two processors and I need help with defining automated MACROS. 我正在两个处理器之间创建一个记录器接口,我需要定义自动MACROS的帮助。

What do I mean? 我什么意思 Let's say I have a logger message defined as LOGGER_MSG_ID_2 that takes two parameter of uint8 and uint16 types. 假设我有一个定义为LOGGER_MSG_ID_2的记录器消息,该消息使用uint8和uint16类型的两个参数。

I have an enum defined as: 我有一个枚举定义为:

typedef enum{
    PARAM_NONE,
    PARAM_SIZE_UINT8,
    PARAM_SIZE_UINT16,
    PARAM_SIZE_UINT32
}paramSize_e;

So LOGGER_MSG_ID_2 will have a bitmap defined as: 因此, LOGGER_MSG_ID_2将具有如下定义的位图:

#define LOGGER_MSG_ID_2_BITMAP   (PARAM_SIZE_UINT16 << 2 | PARAM_SIZE_UINT8)

This bitmap is 1 Byte size, so the maximum number of parameters is 4. Later on I have a list that defines all parameters type according to message ID: 该位图的大小为1字节,因此参数的最大数量为4。稍后,我将根据消息ID定义所有参数类型的列表:

#define ID_2_P0_TYPE                                uint8  // first parameter
#define ID_2_P1_TYPE                                uint16 // 2nd parameter
#define ID_2_P2_TYPE                                0      // 3rd parameter
#define ID_2_P3_TYPE                                0      // 4th parameter

As I said, I have a limitation of 4 parameters, so I would like to define them and let the MACRO decide weather to use them or not. 正如我所说,我有4个参数的限制,因此我想定义它们,然后让MACRO决定是否使用它们。 I defined them as 0 but it can be whatever that works. 我将它们定义为0,但无论如何都可以。

I have other MACROS that uses the bitmap to get all kind of attributes, such as number of parameters and message size. 我还有其他使用位图来获取各种属性的MACROS,例如参数数量和消息大小。

Now it's the tricky part. 现在是棘手的部分。 I want to build a MACRO that creates a bitmap from types. 我想建立一个从类型创建位图的宏。 The reason is that I don't want redundancy between the bitmap and parameters definitions. 原因是我不希望在位图和参数定义之间有冗余。 My problem is that everything I tried failed to compile. 我的问题是我尝试的所有内容均无法编译。

Eventually I would like to have a MACRO such as: 最终,我想要一个宏,例如:

#define GET_ENUM_FROM_TYPE(_type)

that gives me PARAM_SIZE_UINT8, PARAM_SIZE_UINT16 or PARAM_SIZE_UINT32 according to type. 会根据类型为我提供PARAM_SIZE_UINT8,PARAM_SIZE_UINT16或PARAM_SIZE_UINT32。

Limitations: I'm using arm compiler on windows (armcl.exe) and C99. 限制:我在Windows(armcl.exe)和C99上使用arm编译器。 I can't use C11 Generic() . 我不能使用C11 Generic()

I tried the following: 我尝试了以下方法:

#define GET_ENUM_FROM_TYPE(_type)       \
(_type == uint8) ? PARAM_SIZE_UINT8 : \
        ((_type == uint16) ? PARAM_SIZE_UINT16 : \
                ((_type == uint32) ? PARAM_SIZE_UINT32 : PARAM_NONE))

Eventually I want to use it like: 最终我想像这样使用它:

 #define LOGGER_MSG_ID_2_BITMAP              \
    (GET_ENUM_FROM_TYPE(ID_2_P3_TYPE) << 6 | \ 
     GET_ENUM_FROM_TYPE(ID_2_P2_TYPE) << 4 | \ 
     GET_ENUM_FROM_TYPE(ID_2_P1_TYPE) << 2 | \
     GET_ENUM_FROM_TYPE(ID_2_P0_TYPE))

But when I use it, it doesn't compile. 但是,当我使用它时,它不会编译。

I have a table of bitmaps: 我有一张位图表:

uint8 paramsSizeBitmap [] = {
    LOGGER_MSG_ID_1_BITMAP,                         /*  LOGGER_MSG_ID_1   */
    LOGGER_MSG_ID_2_BITMAP,                         /*  LOGGER_MSG_ID_2   */
    LOGGER_MSG_ID_3_BITMAP,                         /*  LOGGER_MSG_ID_3   */
    LOGGER_MSG_ID_4_BITMAP,                         /*  LOGGER_MSG_ID_4   */
    LOGGER_MSG_ID_5_BITMAP,                         /*  LOGGER_MSG_ID_5   */
    LOGGER_MSG_ID_6_BITMAP,                         /*  LOGGER_MSG_ID_6   */
    LOGGER_MSG_ID_7_BITMAP,                         /*  LOGGER_MSG_ID_7   */
    LOGGER_MSG_ID_8_BITMAP,                         /*  LOGGER_MSG_ID_8   */
    LOGGER_MSG_ID_9_BITMAP,                         /*  LOGGER_MSG_ID_9   */
    LOGGER_MSG_ID_10_BITMAP,                        /*  LOGGER_MSG_ID_10  */
};

And I get this error: 我得到这个错误:

line 39: error #18: expected a ")"
line 39: error #29: expected an expression

(line 39 is LOGGER_MSG_ID_2_BITMAP ) (第39行是LOGGER_MSG_ID_2_BITMAP

Where do I go wrong? 我哪里出错了?

----- Edit ----- -----编辑-----

For now I have a workaround that I don't really like. 现在,我有一个我不真正喜欢的解决方法。 I don't use uint64 so I made a use of sizeof() MACRO and now my MACRO looks like this: 我不使用uint64,所以我使用了sizeof() MACRO,现在我的MACRO看起来像这样:

#define GET_ENUM_FROM_TYPE(_type)       \
(sizeof(_type) == sizeof(uint8)) ? PARAM_SIZE_UINT8 : \
        ((sizeof(_type) == sizeof(uint16)) ? PARAM_SIZE_UINT16 : \
                ((sizeof(_type) == sizeof(uint32)) ? PARAM_SIZE_UINT32 : PARAM_NONE))

and my paraemters list is: 我的参数列表是:

#define NO_PARAM                                    uint64

#define ID_2_P0_TYPE                                uint8
#define ID_2_P1_TYPE                                uint16
#define ID_2_P2_TYPE                                NO_PARAM
#define ID_2_P3_TYPE                                NO_PARAM

It works fine but... you know... 它工作正常,但是...您知道...

I believe the solution is to use concatenation operator ## , and helper defines. 我相信解决方案是使用串联运算符##和帮助程序定义。

// These must match your enum
#define HELPER_0      PARAM_NONE
#define HELPER_uint8  PARAM_SIZE_UINT8
#define HELPER_uint16 PARAM_SIZE_UINT16
#define HELPER_uint32 PARAM_SIZE_UINT32

// Secondary macro to avoid expansion to HELPER__type
#define CONCAT(a, b) a ## b

// Outer parenthesis not strictly necessary here
#define GET_ENUM_FROM_TYPE(_type) (CONCAT(HELPER_, _type))

With that GET_ENUM_FROM_TYPE(ID_2_P1_TYPE) will expand to (PARAM_SIZE_UINT16) after preprocessing. 有了这个GET_ENUM_FROM_TYPE(ID_2_P1_TYPE) (PARAM_SIZE_UINT16)在预处理后将扩展为(PARAM_SIZE_UINT16)

Note that suffix in HELPER_*** defines has to match exactly the content of ID_*_P*_TYPE macros. 请注意, HELPER_***中的后缀定义必须与ID_*_P*_TYPE宏的内容完全匹配。 For example HELPER_UINT8 won't work (invalid case). 例如, HELPER_UINT8将不起作用(无效大小写)。 (Thanks @cxw) (感谢@cxw)

The basic problem is that == is not supported for types , only for values . 基本的问题是类型不支持== ,仅值支持 Given 给定

uint8 foo;

you can say foo==42 but not foo == uint8 . 您可以说foo==42但不能说foo == uint8 This is because types are not first class in C. 这是因为类型不是C中的第一类。

One hack would be to use the C preprocessor stringification operator # ( gcc docs ). 一种技巧是使用C预处理程序字符串化运算符#gcc docs )。 However, this moves all your computation to runtime and may not be suitable for an embedded environment. 但是,这会将所有计算移至运行时,可能不适用于嵌入式环境。 For example: 例如:

#define GET_ENUM_FROM_TYPE(_type)   (    \
(strcmp(#_type, "uint8")==0) ? PARAM_SIZE_UINT8 : \
        ((strcmp(#_type, "uint16")==0) ? PARAM_SIZE_UINT16 : \
                ((strcmp(#_type, "uint32")==0) ? PARAM_SIZE_UINT32 : PARAM_NONE)) \
)

With that definition, 有了这个定义,

GET_ENUM_FROM_TYPE(uint8)

expands to 扩展到

( (strcmp("uint8", "uint8")==0) ? PARAM_SIZE_UINT8 : ((strcmp("uint8", "uint16")==0) ? PARAM_SIZE_UINT16 : ((strcmp("uint8", "uint32")==0) ? PARAM_SIZE_UINT32 : PARAM_NONE)) )

which should do what you want, although at runtime. 尽管在运行时,它应该执行您想要的操作。

Sorry, this doesn't directly answer the question. 抱歉,这不能直接回答问题。 But you should reconsider this whole code. 但是您应该重新考虑整个代码。

First of all, _Generic would have solved this elegantly. 首先, _Generic可以_Generic解决此问题。

The dirty alternative to untangle groups of macros like these, would be to use so-called X macros , which are perfect for cases such as "I don't want redundancy between the bitmap and parameters definitions". 像这样解开宏组的肮脏替代方法是使用所谓的X宏 ,它非常适合诸如“我不想在位图和参数定义之间进行冗余”之类的情况。 You can likely rewrite your code with X macros and get rid of a lot of superfluous defines and macros. 您可能可以使用X宏重写代码,并摆脱许多多余的定义和宏。 How readable it will end up is another story. 最终的可读性是另一个故事。

However, whenever you find yourself this deep inside some macro meta-programming jungle, it is almost always a certain indication of poor program design. 但是,每当您发现自己位于宏元编程丛林的深处时,几乎总是表明程序设计不佳。 All of this smells like an artificial solution to a problem that could have been solved in much better ways - it is a "XY problem" . 所有这些都闻起来像是一种人工解决方案,可以以更好的方式解决问题-这是“ XY问题” (not to be confused with X macros :) ). (不要与X宏混淆:))。 The best solution most likely involves rewriting this entirely in simpler ways. 最好的解决方案很可能涉及以更简单的方式完全重写它。 Your case doesn't sound unique in any way, it seems that you just want to generate a bunch of bit masks. 您的手机壳听起来并没有什么独特之处,似乎您只是想生成一堆位掩码。

Good programmers always try to make their code simpler, rather than making it more complex. 好的程序员总是试图使他们的代码更简单,而不是使其变得更复杂。


In addition, you may have more or less severe bugs all over the code, caused by the C language type system. 此外,由于C语言类型系统,整个代码中或多或少都存在严重的错误。 It can be summarized as: 可以总结为:

  • Bit shifts or other bitwise arithmetic should never be used on signed types. 绝对不能在有符号类型上使用移位或其他按位算术。 Doing so can lead to all manner of subtle bugs and poorly-defined behavior. 这样做可能导致各种细微的错误和定义不明确的行为。
  • Enumeration constants are always of type int which is signed. 枚举常量始终是带符号的int类型。 You should avoid mixing them with bitwise arithmetic. 您应该避免将它们与按位算术混合使用。 Avoid enums entirely for programs like this. 完全避免为此类程序使用枚举。
  • Small integer types such as uint8_t or uint16_t get implicitly type promoted to int when used in an expression. 在表达式中使用时,小整数类型(例如uint8_tuint16_t会隐式地提升为int类型。 Meaning that the C language will bandwagon most of your attempts to get the correct type and replace everything with int anyway. 这意味着C语言将使您获得正确类型并将大部分内容替换为int大多数尝试大行其道。
  • The resulting type of your macros will be int , which is not what you want. 宏的结果类型将是int ,这不是您想要的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM