C - 将枚举用于位标志 - 警告 : enumerated type mixed with another type

标签 c enums arm keil 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);

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

warning: #188-D: enumerated type mixed with another type

警告是因为 LED_RED | LED_绿色 | LED_YELLOW 转换为整数,不是 LedType

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

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

我正在使用 Keil µVision IDE 对基于 ARM 的微 Controller (STM32) 进行编程。

我的问题

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


全文

我正在为连接到多个 LED 的基于 ARM 的 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);

我收到警告:

warning: #188-D: enumerated type mixed with another type

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

最佳答案

I would prefer to use an enum instead of defines for LED flags because I prefer to encapsulate theme in one meaningful type/object.

这很好,但请记住两点:

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

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

一个这样的小问题是左移一个带符号的整数常量 1 .这是类型 int并签名,所以在 32 位系统上,1 << 31将意味着未定义的行为错误。因此,始终为您的整数常量添加无符号后缀:始终使用 1u << n而不是 1 << n .

I get the warning: warning: #188-D: enumerated type mixed with another type

是的,因为该函数需要一个 uint32_t但你传递了一个 int , 因为表达式中的所有操作数 LED_RED | LED_GREEN | LED_YELLOWint - 它们是如上所述的枚举常量。您应该重写函数以获取 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 检查器。

关于C - 将枚举用于位标志 - 警告 : enumerated type mixed with another type,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57391948/

相关文章:

c - 我们如何将 FILE* 转换为 HANDLE?

Java:枚举的等价类

c++ - 以某种方式将 If/Else 转换为开关

gcc - 在 GCC 中使用内联 ARM 汇编时优化所用寄存器

c - cortex-m0plus 上的浮点库

c - 编译 [警告] 多字符字符常量 [-Wmultichar] 时出错

C - Code::Blocks 13.12:哪一个可以正常工作,或者两者都可以?两者有区别吗?还是C标准允许的?

c - 在C、linux中通过poll fd获取unix socket连接是否需要额外的参数或设置?

java - 是否可以使用方法创建一个空的 Java 枚举类型?

安卓模拟器3.0内核