If you can move the variable length buffer to the end of the structure, and you don't care about portability, you can do this. This example relies on #pragma pack to align fields on 8 byte boundaries.
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;
}
Output
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
Notes
As you can see, the address of size is 8 more than the address of name, and the address of data is 8 more than the address of size. If your target is a 32-bit architecture, you could use #pragma pack(4).
Warning
If you are trying to access addresses that are not on machine word boundaries, this might generate very slow code on x86 and x64 architectures, and code that crashes with SIGBUS on RISC architectures.
Trivia
I first saw structure definitions like this in Microsoft driver code.
data, unless it has a hard-coded length.datawas lastdatawas at the end of the structure.data[]to the end and lookup flexible arrays.