Crisis of Style
2006-05-31
I was reviewing some code today, which had the following fragment:
struct option { char *name; char *format; struct universe *universe; unsigned code; int refcnt; }; struct option *new_option (name, file, line) const char *name; const char *file; int line; { struct option *rval; int len; len = strlen(name); rval = dmalloc(sizeof(struct option) + len + 1, file, line); if(rval) { memcpy(rval + 1, name, len); rval->name = (char *)(rval + 1); } return rval; }
So this is a pretty basic constructor. The code is correct. My concern is that it is not as straightforward as it could be, in that it allocates a single block of memory and then points the variable size data, name, after the fixed size data. If I were going to write it, I would have allocated two blocks of memory:
struct option *new_option (name, file, line) const char *name; const char *file; int line; { struct option *rval; int len; rval = dmalloc(sizeof(struct option), file, line); if (rval == NULL) { return NULL; } len = strlen(name); rval->name = dmalloc(len+1, file, line); if (rval->name == NULL) { dfree(rval); return NULL; } memcpy(rval->name, name, len); /* NUL-terminated by dmalloc() */ return rval; }
This involves a bit more code, and two memory allocations instead of one. So there is a performance penalty, although it is so small I think you'd have a hard time measuring it in practice. However, I think it's less "tricky", and therefore easier to read, meaning:
Is it actually easier to understand with two allocations, or am I crazy?
Shane Kerr
shane@time-travellers.org