是否通过定义良好的结构访问可变长度存储对象?

时间:2019-07-15 18:30:46

标签: c struct

我有一个可变长度的数据记录,该数据记录我使用一个结构进行建模。给定一个内存对象,我想知道C语言标准中是否定义了以下内容。

我使用以下结构对问题进行建模:

struct record
{
   uint32_t type;
   union
   {
     uint8_t u8;
     uint16_t u16;
     uint34_t u32;
   };
};

有关平台,

sizeof(struct record) == 8

下面的转换是否定义明确?

alignas(uint32_t) uint8_t buf[5];
struct record *rec = (struct record*)buffer;

如何通过指针访问存储对象。即是访问权限

uint8_t x = rec->u8;
rec->u8 = x+1;

定义好了吗?我完全希望u16和u32访问的定义不正确,并且可能导致异常。

可以参考c11标准。

感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

违反别名行为

关于:

alignas(uint32_t) uint8_t buf[5];
struct record *rec = (struct record*)buf;
uint8_t x = rec->u8;

(请注意,原件中的buffer显然是一个错误,在此处已更正为buf。)

这违反了C 2018 6.5 7(C 2011具有相同的文本),内容为:

  

只能通过具有以下类型之一的左值表达式访问对象的存储值:

     

-与对象的有效类型兼容的类型,

     

-与对象的有效类型兼容的类型的限定版本,

     

-一种类型,它是与对象的有效类型相对应的有符号或无符号类型,

     

-一种类型,是与对象的有效类型的限定版本相对应的有符号或无符号类型,

     

-集合或联合类型,其成员中包括上述类型之一(递归地包括子集合或包含的联合的成员),或

     

-字符类型。

buf是5 uint8_t的数组。可通过rec的{​​{1}}访问它。与上面列出的情况进行比较:

  • struct record与5 struct record的数组不兼容。
  • uint8_t不是与5 struct record数组兼容的类型的合格版本。
  • uint8_t不是与5 struct record数组相对应的有符号或无符号类型。
  • uint8_t是聚合联合类型,但是其成员都不与5 struct record的数组或上面列出的任何其他情况兼容。
  • uint8_t不是字符类型。

C标准中存在一些歧义或不完整。一个人可能会认为struct record不是访问rec->u8,而是仅使用struct record来定位struct record成员,然后访问它。通过这种解释,可以满足6.5 7,因为u8几乎可以肯定是字符类型,因此可以满足最后一种情况。 (除非实现为扩展整数类型定义,否则它必须是字符类型。)我不会依赖于C标准的这种解释。但是,uint8_tu16成员将不匹配任何大小写,因此使用它们肯定会违反C 2018 6.5 7。

解决方案

根据需要解释u32中字节的正确方法是将它们复制到结构中:

buf

其他问题

标题询问“可变长度存储对象”,但是#include <string.h> // For memcpy. … struct record MyRecord; memcpy(MyRecord, buf, SomeLength); 的大小为5个字节,并且没有变化。

buf中,如果要运行,最好将alignas(uint32_t) uint8_t buf[5];设为alignas