Reputation: 139
I've read about the Cello fat pointer library and wanted to know if prepending a header to some data is actually allowed in C, e.g. something like this:
struct header
{
size_t length;
};
char* create_string(const char* cstr)
{
void* ret = malloc(sizeof(struct header)+strlen(cstr)+1);
((struct header*)ret)->length = strlen(cstr);
strcpy((char*)ret + sizeof(struct header), cstr);
return (char*)ret + sizeof(struct header);
}
size_t get_length(const char* sized_string)
{
struct header* tmp = sized_string - sizeof(struct header);
return tmp->length;
}
This example is a string, but it could be anything else that is stored, maybe even something that isn't an array, in which case the header could have different kinds of metadata.
I know that sds uses flexible array members, but that requires c99 and isn't quite as flexible as this aproach (unless you just used a generic char array and recast it as needed).
Specifically in this question people say the following is not actually portable:
struct header {
size_t len;
unsigned char data[1];
};
Because accessing data beyond the first element is UB. Another thing is that the lines ((struct header*)ret)->length = strlen(cstr);
and struct header* tmp = sized_string - sizeof(struct header);
look wrong to me (because of the pointer casts) and I don't see a better way to write them.
Upvotes: 3
Views: 4699
Reputation: 6391
Your example places and reads from fixed offsets only. So at least the pointer arithmetic is perfectly legal. At least as long as the type is just a char
.
What is problematic though is alignment. This is not violating the language standard yet, but the alignment of the actual data is worse than what e.g. compilers on x86 will provide by default.
So if the compiler would by default align to 8 bytes (gcc and msvc on x86) or 16 bytes (on x64), your example code provides only half the alignment.
This can be illegal, if the compiler was assuming aligned memory (which would otherwise had been ensured by matching malloc
implementation, as well as padding in stack layout and structs). Depending on the architecture, it can even cause errors, as instructions may require a minimum alignment.
Upvotes: 6