2017-10-17 51 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