如果您可以将可变长度缓冲区移动到结构的末尾,并且不关心可移植性,则可以这样做。此示例依赖于
#pragma pack
将字段对齐到8字节边界。
variable_length.h
#ifndef VARIABLE_LENGTH_H
#define VARIABLE_LENGTH_H
#include <stdint.h>
#pragma pack(8)
typedef struct {
uint8_t name;
uint8_t time;
uint8_t etc;
size_t size;
} header_t;
typedef struct {
uint8_t name;
uint8_t time;
uint8_t etc;
size_t size;
uint8_t data[];
} data_t;
#pragma pack()
#endif
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "variable_length.h"
header_t *create_buffer(char *buffer_name) {
size_t buffer_size = strlen(buffer_name) + 1;
size_t size = sizeof(header_t) + buffer_size;
data_t *result = calloc(1, size);
if (NULL == result) {
perror("Could not allocate memory for buffer");
exit(1);
}
result->name = 'A';
result->time = 1;
result->etc = 'x';
result->size = buffer_size;
strncpy((char *) result->data, buffer_name, buffer_size);
return (header_t *) result;
}
int main(void) {
header_t *result = create_buffer("example buffer");
data_t *example = (data_t *) result;
printf("name = %c\n", example->name);
printf("time = %d\n", example->time);
printf("etc = %c\n", example->etc);
printf("size = %lu\n", example->size);
for (int index = 0; index < example->size; index++) {
printf("%c", example->data[index]);
}
printf("\n\n");
printf("address of name = %p\n", &example->name);
printf("address of time = %p\n", &example->time);
printf("address of etc = %p\n", &example->etc);
printf("address of size = %p\n", &example->size);
printf("address of data = %p\n", example->data);
return 0;
}
输出
name = A
time = 1
etc = x
size = 15
example buffer
address of name = 0xf20260
address of time = 0xf20261
address of etc = 0xf20262
address of size = 0xf20268
address of data = 0xf20270
注释
如您所见,size
的地址比name
的地址多8个字节,data
的地址比size
的地址多8个字节。如果您的目标是32位架构,则可以使用#pragma pack(4)
。
警告
如果您试图访问不在机器字边界上的地址,则这可能会在x86和x64架构上生成非常缓慢的代码,并在RISC架构上崩溃并出现SIGBUS
。
趣闻
我第一次看到这样的结构定义是在Microsoft驱动程序代码中。
data
是最后一个,你可以这样做。 - ikegamidata[]
移动到末尾并查找灵活数组。 - dxiv