C-对位标记使用枚举-警告:枚举类型与其他类型混合

时间:2019-08-07 10:08:28

标签: c enums arm embedded bitflags

简短说明:

我正在将枚举常量作为位标志传递给期望枚举类型作为输入的函数,如下所示:

// Enumeration type
typedef enum
{
    LED_RED    =        (1 << 0),
    LED_GREEN  =        (1 << 1),
    LED_YELLOW =        (1 << 2),
    LED_ORANGE =        (1 << 3),
} LedType;

...

// Function declaration
void setOnLed(LedType led);

...

// Function call
setOnLed(LED_RED | LED_GREEN | LED_YELLOW);

当我调用该函数时,会收到警告:

  

警告:#188-D:枚举类型与其他类型混合

详细信息:

我正在为一个基于ARM的MCU编写程序,该程序已连接到多个LED。在程序的许多地方,我们都将打开/关闭,切换和闪烁LED的不同组合。为了使这一过程变得简洁明了,我想编写几个函数,这些函数以输入的方式组合任何LED并以相同的方式进行操作。

我创建了一个名为struct的{​​{1}},它具有一个LED的硬件配置以及一个LedConfig的阵列,其中包含每个LED的配置:

LedConfig

现在,我想要一种简单的方法,将多个LED传递给一个函数并循环处理它们。

我为每个LED创建了许多位标志:

typedef struct
{
    // Hardware configurations of a LED
    ...
} LedConfig;

...

LedConfig LedArry[LEDS_LED_COUNT] = 
{
    [0] = { /* Red LED config    */ }, 
    [1] = { /* Green LED config  */ }, 
    [2] = { /* Yellow LED config */ }, 
    [3] = { /* Orange LED config */ }
};

定义了一个功能:

// Number of LED's defined in the system
#define LED_COUNT           4

// LED flags, for usage in LED's function
#define LED_RED             (1 << 0)
#define LED_GREEN           (1 << 1)
#define LED_YELLOW          (1 << 2)
#define LED_ORANGE          (1 << 3)

现在我可以通过按位或操作将LED传递给功能:

void setOnLed(uint32_t led)
{
    uint32_t bitMask = 1;
    for(int i = 0; i < LED_COUNT; i++)
    {
        if(led & bitMask)
        {
            LedConfig* ledConfig = &LedArry[i];
            // Turn on LED ...
        }
        bitMask <<= 1;
    }
}

这很好,但是...

我希望使用setOnLed(LED_RED | LED_GREEN | LED_YELLOW); 而不是为LED标志定义,以便将主题封装在一个有意义的类型/对象中。

我用枚举替换了定义:

enum

并修改了typedef enum { LED_RED = (1 << 0), LED_GREEN = (1 << 1), LED_YELLOW = (1 << 2), LED_ORANGE = (1 << 3), } LedType; 函数输入以获取枚举类型:

setOnLed

当我用几个LED调用函数时:

void setOnLed(LedType led)
{
    // ...
}

我得到警告:

  

警告:#188-D:枚举类型与其他类型混合

警告是因为setOnLed(LED_RED | LED_GREEN | LED_YELLOW); 转换为整数而不是LED_RED | LED_GREEN | LED_YELLOW

我可以通过将LED组合添加到LedType枚举中来避免警告,但这意味着我必须添加所有可能的组合...并且当将更多LED添加到MCU时,它将变得非常混乱。 ..

我可以使用数组作为函数的输入,但是在调用函数时需要更多代码。

我的问题

是否有避免这种警告的简单安全方法,还是将所有LED封装在一个有意义的类型/对象中的另一种方法,以便我可以轻松地将它们传递给函数并进行循环处理?

注意LedType来自stdint.h,是32位无符号整数。

1 个答案:

答案 0 :(得分:1)

  

我宁愿使用枚举代替对LED标志的定义,因为我更喜欢将主题封装在一个有意义的类型/对象中。

这很好,但请记住两点:

  • 枚举常量的类型(在您的情况下为LED_RED)始终为int类型,并且已签名。
  • 枚举类型的类型,LedType是实现定义的。如果使用的值适合一个整数,则编译器可以选择较小的整数类型。

通常,由于整数提升和按位运算符引起的各种麻烦,您通常希望避免在嵌入式系统中使用带符号类型。

一个打h的例子是将有符号整数常数1左移。这是int类型并已签名,因此在32位系统上,1 << 31表示未定义的行为错误。因此,请始终对整数常量进行无符号后缀处理:请始终使用1u << n代替1 << n

  

我得到警告:warning: #188-D: enumerated type mixed with another type

是的,因为该函数需要一个uint32_t,但是您传递了一个int,因为表达式LED_RED | LED_GREEN | LED_YELLOW中的所有操作数都是int-它们是如上所述的枚举常量。您应该改写函数,以LedType作为参数。

示例:

// led.h

typedef enum
{
  LED_NONE   = 0u,
  LED_RED    = 1u << 0,
  LED_GREEN  = 1u << 1,
  LED_YELLOW = 1u << 2,
  LED_ORANGE = 1u << 3,
  LED_ALL = LED_RED | LED_GREEN | LED_YELLOW | LED_ORANGE;
} led_t;

#define LED_PORT PORTX


void set_led (led_t leds);

// led.c

#include "led.h"

void set_led (led_t leds)
{
  // this assuming you'll want to use the function both to set and clear leds
  uint32_t led_port = LED_PORT;
  led_port &= (uint32_t) ~LED_ALL;
  led_port |= (uint32_t) leds;
  LED_PORT = (uint32_t) leds;
}

严格来说,(uint32_t)强制类型转换不是必需的,但会令学究的编译器和MISRA-C检查器感到满意。