2017-04-02 93 views
0

我有以下结构的库:该库的自定义用户数据保留

struct frame_meta_data 
{ 
    uint8_t id; 
    uint8_t general_field_1; 
    uint8_t general_field_2; 
    ... 
    uint8_t user_data[16]; 
}; 

而且我希望用户能够自定义的数据保存到帧的对象(这是什么user_data字段用于)。

尝试投放USER_DATA到自定义结构然而,当:

frame_meta_data cur_frame; 
... 
#define USER_HDR ((struct my_user_header*)cur_frame.user_data) 

我得到以下错误:

 
warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing] 
#define USER_HDR ((struct my_user_header*)cur_frame.user_data) 

我如何解决此问题?

在此先感谢。

+1

不要投。使用'memcpy'。 – melpomene

+0

@melpomene它会伤害我的表现... –

回答

1

C标准不允许重新解释这样的地址。严格的别名意味着编译器可以自由地假定不同类型的两个指针永远不会指向同一个对象,然后根据这些对象进行各种优化。

您的代码违反了C标准,并因此导致了未定义的行为。但是你可以修复它。像墨尔波墨涅的意见建议,不投,而是用memcpy

struct my_user_header obj; 
memcpy(&obj, cur_frame.user_data, sizeof obj); 

另外,一些编译器允许你写不规范的代码编译器选项,如GCC的-fno-strict-aliasing

1

如果您知道自己在做什么,可以禁用该警告。但是有一个潜在的问题。

假设您要使用的结构包含大于1个字节的内容。例如一个4字节的整数。现在,如果您只是将该user_data字段转换为您的结构,那么int可能不会按照它应该与4字节边界对齐。这可能会导致某些体系结构中出现运行时异常。

使用memcpy应该可以解决这个问题。并删除警告。

+0

如果user_data与4对齐,它仍会如此吗? –

+0

如果user_data与4对齐,则4字节类型不会有任何问题,但8字节类型可能有问题。 – aragaer

1

我怀疑这是因为您在涉及数据区域的多次访问中涉及到这个USR_DATA宏表达式的拷贝,并且它让编译器感到困惑。或者,您甚至可以将USR_DATA访问与底层char数组的操作混合在一起。

如果数据区只按照给定的用户数据类型进行初始化和访问,则不会出现任何别名。确保你以这种方式使用它。

我将提供一个外部(如在非内联,外部连接)API函数,给定一个帧的对象,返回一个void *到相关联的用户数据:

struct foobar *fbs = (struct foobar *) frame_get_userdata(fr); 

// now work just with fbs 

铸造不必要;这是我的风格。

根据用户数据之前的内容,它可能没有适合任意使用的对齐方式。如果该选项可用,修复该问题的一个简单方法是将其作为第一个struct成员。否则,存在各种相当便携的技巧,涉及在char阵列与各种类型(如long double等)之间建立联合,或者使用编译器特定的构造,如使用GCC的__attribute__((aligned))