簡體   English   中英

C - 使用枚舉作為位標志 - 警告:枚舉類型與另一種類型混合

[英]C - Using enum for bit flags - warning: enumerated type mixed with another type

我將枚舉常量作為位標志傳遞給需要枚舉類型作為輸入的函數,如下所示:

// 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 LED_RED | LED_GREEN | LED_YELLOW LED_RED | LED_GREEN | LED_YELLOW轉換為整數,而不是LedType

我可以通過向LedType枚舉添加 LED 組合來避免警告,但這意味着我必須添加所有可能的組合......如果我向enum添加更多 LED 選項,它會變得非常混亂......

我可以使用數組作為函數的輸入,但是在調用函數時需要更多的代碼,我更喜歡簡單的函數調用來設置 LED。

我正在使用 Keil µVision IDE 對基於 ARM 的微控制器 (STM32) 進行編程。

我的問題

是否有一種簡單安全的方法來避免此警告或另一種方法將所有 LED 封裝在一個有意義的類型/對象中,以便我可以輕松地將它們傳遞給函數並在循環中處理它們?


完整的故事

我正在為連接到多個 LED 的基於 ARM 的 MCU 編寫程序。 在程序的許多地方,我們將打開/關閉、切換和閃爍 LED 的不同組合。 為了使這個干凈和簡單,我想編寫幾個函數,將 LED 的任意組合作為輸入,並對所有函數執行相同的操作。

我創建了一個struct名為LedConfig與LED和陣列的硬件配置LedConfig包含每個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 */ }
};

現在,我想要一種簡單的方法來將幾個 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 位整數。

我更喜歡使用枚舉而不是定義 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中的所有操作數LED_RED | LED_GREEN | LED_YELLOW 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 檢查器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM