C - 对位标志使用枚举 - 警告:枚举类型与另一种类型混合



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

// 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:枚举类型与另一种类型混合

该警告是因为LED_RED | LED_GREEN | LED_YELLOW被转换为整数,而不是LedType

我可以通过将 LED 组合添加到LedType枚举来避免警告,但这意味着我必须添加所有可能的组合......如果我在enum中添加更多的 LED 选项,它会变得非常混乱......

我可以使用数组作为函数的输入,但在调用函数时需要更多代码,我更喜欢简单的函数调用来设置 LED。

我正在使用Keil μVision IDE对基于ARM的微控制器(STM32(进行编程。

我的问题

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


全文

我正在为一个基于ARM的MCU编写一个程序,该MCU连接到多个LED。在程序的许多地方,我们将撕开/关闭,切换和闪烁LED的不同组合。为了使这变得干净和简单,我想编写几个函数,这些函数作为输入获取LED的任意组合,并对所有函数执行相同的操作。

我创建了一个名为LedConfigstruct,其中包含 LED 的硬件配置和包含每个 LED 配置的LedConfig数组:

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 */ }
};

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

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

// 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)

定义了一个函数:

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;
}
}

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

setOnLed(LED_RED | LED_GREEN | LED_YELLOW);

这工作正常,但是...

我宁愿使用enum而不是 LED 标志的定义,以便将主题封装在一个有意义的类型/对象中。

我用枚举替换了定义:

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

并修改setOnLed函数输入以获取枚举类型:

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

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

setOnLed(LED_RED | LED_GREEN | LED_YELLOW);

我收到警告:

警告:#188-D:枚举类型与另一种类型混合

注意uint32_t来自 stdint.h,是一个无符号的 32 位整数。

我更喜欢使用 enum 而不是 LED 标志的定义,因为我更喜欢将主题封装在一个有意义的类型/对象中。

这很好,但请记住两件事:

  • 枚举常量的类型(LED_RED在您的情况下(始终是带符号的int类型。
  • 枚举类型的类型,LedType在你的例子中是实现定义的。如果使用的值适合一个整数类型,编译器可以选择较小的整数类型。

通常,您需要避免在嵌入式系统中使用有符号类型,因为整数提升和按位运算符的各种打嗝。

一个这样的打嗝是左移有符号整数常量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)cast不是必需的,但会满足迂腐的编译器和MISRA-C检查器。

最新更新