2017-10-17 53 views
0

設置:部分字節訪問

  1. 我在C99定義枚舉:

    enum MY_ENUM {TEST_ENUM_ITEM1, TEST_ENUM_ITEM2, TEST_ENUM_ITEM_MAX}; 
    
  2. 我保證用編譯時斷言TEST_ENUM_ITEM_MAX不超過UINT16_MAX。我假設小字節順序。

  3. 我有以下參數的串行化 - 進入 - 緩衝功能:

    PutIntoBuffer(uint8_t* src, uint32_t count); 
    
  4. 我序列的可變保持一個值到緩衝區中。對於這個任務,我訪問變量,抱着枚舉,就像這樣:

    enum MY_ENUM testVar = TEST_ENUM_ITEM; 
    
    PutIntoBuffer((uint8_t*) &testVar, sizeof(uint16_t)); 
    

問:它是合法的以這種方式來訪問枚舉(這是一個int)? C標準是否能保證預期的行爲?

+0

如果枚舉可以比U8_MAX更大然後它可能會奇怪它轉換爲U8指針。 – Fredrik

回答

1

這是合法的,因爲「它將工作,如果int是16位」。它也不違反任何指針別名規則,只要您使用像uint8_t這樣的字符類型即可。 (雖然反序列化是另一回事。)

但是,代碼不是可移植的。在int爲32位的情況下,枚舉常量也會變成32位,這可能與枚舉變量本身一樣。然後代碼會變成依賴性,你最終可能會讀垃圾。根據UINT16_MAX檢查TEST_ENUM_ITEM_MAX並不能解決此問題。

序列化枚舉正確的方法是要使用的保證是8位的預生成的只讀查表,像這樣:

#include <stdint.h> 

enum MY_ENUM {TEST_ENUM_ITEM1, TEST_ENUM_ITEM2, TEST_ENUM_ITEM_MAX}; 

static const uint8_t MY_ENUM8 [] = 
{ 
    [TEST_ENUM_ITEM1] = TEST_ENUM_ITEM1, 
    [TEST_ENUM_ITEM2] = TEST_ENUM_ITEM2, 
}; 

int main (void) 
{ 
    _Static_assert(sizeof(MY_ENUM8)==TEST_ENUM_ITEM_MAX, "Something went wrong"); 
} 

指定初始化語法提高了完整性的數據,應該在維護期間更新枚舉。同樣,靜態斷言將確保列表包含正確數量的項目。

+0

在什麼情況下我該讀INT beeing 32位和小字節序的垃圾? UINT16_MAX的值是否可以安全讀取? – user259819

+0

@ user259819啊,垃圾(在所有零形式)將只與大端發生。但無論如何,我們沒有理由用怪異的,不可移植的指針技巧時,你可以得到在編譯時產生的確定性,可移植的代碼。 – Lundin