On 02/18/2014 01:12 PM, janus wrote:
....
That's a great improvement. First of all, it includes the code that you
gave in your first message, code which was entirely missing from more
complete code that you showed in your second message. That code now
appears in context, and that context confirms Ben Bacarisse's
explanation of the use of ts+1, which I misunderstood. That code
over-allocates space for the struct, and ts+1 points to the first byte
of excess space, which is where the actual contents of the string is stored.
Now, I'm finally prepared to answer your original question. The approach
used in the actual Lua code has one key advantage: it has defined
behavior even when using C90.
However, since I don't believe in catering to old standards (C99 is
already 14 years old), I would favor taking advantage of C99's concept
of flexible array members. Your suggested alternative code:
ts = &luaC_newobj(L, LUA_TSTRING, totalsize, list, 0)->ts;
ts->tsv.len = l;
ts->tsv.hash = h;
ts->tsv.reserved = 0;
memcpy(ts.string, str, l*sizeof(char));
ts.string[l] = '\0'; /* ending 0 */
is inherently wrong because the use of ts.string instead of ts->string.
Even with that correction, it's still wrong, given that "ts" has the
type TString*, and TString is a union type, not a struct type. However,
if TString were modified as follows:
typedef union TString {
L_Umaxalign dummy; /* ensures maximum alignment for strings */
struct {
CommonHeader;
lu_byte reserved;
unsigned int hash;
size_t len; /* number of characters in string */
char string[];
} tsv;
} TString;
then your code would be correct if you replaced ts.string with
ts->tsv.string, and I would strongly favor using that approach instead
of the one used in the actual Lua implementation.
However, with the original code, both ts and ts+1 are guaranteed (by
whoever typedefs L_Umaxalign - the C standard guarantees no such thing)
to be maximally aligned. With the above modification, ts is guaranteed
to be maximally aligned, but ts->tsv.string is not. The phrase "ensures
maximum alignment for strings" is ambiguous - I'm not sure if it would
be considered to apply to ts->tsv.string, or only to ts.
If use of C2011 were permitted, there would be no need for "dummy", and
therefore no need for a union (making things a bit simpler), in order to
ensure that ts->string was maximally aligned:
#include <stddef.h> // for max_align_t
typedef struct TString {
CommonHeader;
lu_byte reserved;
unsigned int hash;
size_t len; /* number of characters in string */
_Alignof(max_align_t) char string[];
} TString;