我们可以用链接中指定的零长度数组初始化结构:
我正在使用以下结构:
typedef unsigned char UINT8;
typedef unsigned short UINT16;
typedef struct _CommandHeader
{
UINT16 len;
UINT8 payload[0];
} CommandHeader;
typedef struct _CmdXHeader
{
UINT8 len;
UINT8 payload[0];
} CmdXhHeader;
现在 CommandHeader.payload 应该指向/包含 CmdXHeader 结构。即内存应该是这样的:
-------------------------------------------------------------
| CommandHeader.len | CmdXHeader.len | CmdXHeader.payload ....|
-------------------------------------------------------------
我可以轻松地将 CmdXHeader/CommandHeader malloc 到自定义长度。但是如何为 CmdXHeader 有效载荷赋值或如何将 CmdXHeader 对象链接到 CommandHeader.payload?
我的解决方案
感谢大家的回复。我通过以下方式解决了它:
//Get the buffer for CmdXHeader:
size_t cmdXHeader_len = sizeof(CmdXHeader) + custom_len;
CmdXHeader* cmdXHeader = (CmdXHeader*) malloc(cmdXHeader_len);
//Get a temporary pointer and assign the data to it
UINT8* p;
p[0] = 1;
p[2] = 2;
.......
//Now copy the memory of p to cmdXHeader
memcopy(cmdHeader->payload, p, custom_len);
// allocate the buffer for CommandHeader
CommandHeader* commandHeader = (CommandHeader*) malloc (sizeof (CommandHeader) + cmdXHeader_len);
// populate the fields in commandHeader
commandHeader->len = custom_len;
memcpy(commandHeader->payload, cmdXHeader, cmdXHeader_len);
现在 commandHeader 对象有了所需的内存,我们可以用任何我们想要的方式进行类型转换...
最佳答案
在标准 C 中,结构末尾或其他任何地方的零长度数组实际上是非法的(更准确地说是约束违规)。它是特定于 gcc 的扩展。
它是“struct hack”的几种形式之一。一种稍微更便携的方法是定义一个长度为 1 而不是 0 的数组。
C 语言的创造者丹尼斯·里奇 (Dennis Ritchie) 称其为“与 C 实现毫无根据的亲密关系”。
ISO C 标准的 1999 修订版引入了一种称为“灵活数组成员”的功能,这是一种更可靠的实现方式。大多数现代 C 编译器都支持此功能(不过我怀疑 Microsoft 的编译器不支持)。
这在 comp.lang.c FAQ 的问题 2.6 中进行了详细讨论。 .
至于如何访问它,无论使用哪种形式,您都可以像对待任何数组一样对待它。在大多数上下文中,成员的名称会衰减为一个指针,从而允许您对其进行索引。只要分配了足够的内存,就可以执行以下操作:
CommandHeader *ch;
ch = malloc(computed_size);
if (ch == NULL) { /* allocation failed, bail out */ }
ch.len = 42;
ch.payload[0] = 10;
ch.payload[1] = 20;
/* ... */
显然这只是一个粗略的轮廓。
请注意 sizeof
, 当应用于 CommandHeader
类型时或该类型的对象,将为您提供不包含灵活数组成员的结果。
另请注意,以下划线开头的标识符是为实现保留的。你不应该在你自己的代码中定义这样的标识符。无需为 typedef 名称和结构标记使用不同的标识符:
typedef struct CommandHeader
{
UINT16 len;
UINT8 payload[0];
} CommandHeader;
我还建议使用标准类型 uint16_t
和 uint8_t
, 在 <stdint.h>
中定义(假设您的编译器支持它;它在 C99 中也是新的)。
(实际上下划线开头的标识符的规则稍微复杂一些。引用 N1570 ,标准的最新草案,第 7.1.3 节:
- All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.
- All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces.
还有几类保留标识符。
但是与其弄清楚哪些标识符在文件范围内可以安全使用,哪些在其他范围内可以安全使用,避免定义任何以下划线开头的标识符要容易得多。)
关于c - 如何在 C 中使用零长度数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14611322/