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