Clint Olsen wrote:
I did a Google about this, and I've seen this covered quite a few times -
some leading to useful tricks with offsetof() to discern alignment and
others using a big-union of intrinsic types to discern what the compiler
would do with this kind of data and act accordingly. Others claimed it
couldn't be done or it wasn't worth it.
Rather than dive into the how, I wanted to discuss more of the _why_ since
that was asked a few times and nobody replied to that question.
The best examples I can give are keeping related data together and avoiding
fragmentation by multiple (perhaps unecessary) malloc calls. When writing
ADT libraries, it would be nice to keep node/link info together with the
associated data. The alternative is to force the user to include a
node/link struct in their data structure and force the library writer to
expose his API unecessarily. Another situation is to be able to write a
debugging memory allocator where you have extra space at the beginning of
the allocation section to store information such as file/line info of where
it occurred. Richard's MemTrack library had an example of this in 'C
Unleashed'. Then the info is just a known offset away from the user
pointer. Otherwise you would need a rather complex translation scheme to
tie the addresses to the alloc info since pointer values themselves cannot
be portably used.
I'm just curious as to what others think of this technique and if it's
really worth the effort.
You don't say so explicitly, but I guess you're looking
for a portable way to answer the question "What is the most
restrictive alignment required by this implementation, for
any data type whatsoever?" (The techniques you mention are
already capable of answering the question for any particular
type T, but they're no good for the more general question
because the set of types is extensible.)
IMHO, the question is not all that interesting except to
the implementors of the compiler and library. They obviously
need the answer, but since they need not obtain it portably
they are free to resort to other means -- foreknowledge is
perhaps the most typical. For the other two uses you mention:
- For ADTs you'd like (I guess) to start each node with
your own header of structural data, and then make a copy
of the "payload" data just after it. To ensure proper
alignment of the payload you want to pad your header to
a multiple of the maximal alignment.
That's one approach, but it's certainly not the only
way. If the payload is of fixed length you can easily
plant your structural data *after* the payload data.
Or you could go for greater flexibility and avoid
copying the data altogether: segregate the structural
data from the payload entirely, and use a `void*' to
point to the payload. This latter approach has the
advantage that a single payload can exist simultaneously
in a three hash tables, two skip lists, and a partridge
in a B-tree.
In short, I don't see a compelling reason for ADT APIs
to require the alignment information. Convenient for
some kinds of implementation, perhaps, but not vital.
- For a debugging memory manager, my advice is *not* to
keep your structural information close to the payload.
Of all memory locations, those adjacent to the allocated
areas are surely the most vulnerable to being trashed
by fencepost errors, runaway strcpy(), and the like.
In my own debugging malloc() -- I guess pretty much
everybody eventually gets around to writing one -- I
keep the structural data separate from the allocated
areas as much as possible. I don't do arithmetic on
the argument to free() to discover the size of the
block; instead, I look up the address in a skip list.
A lookup failure means a bad argument value -- double-
freeing, or freeing a garbage pointer -- and I can
detect this without running off the rails.
On the other hand, there *is* one place where it would
help if I could determine the maximal alignment: I plant
pre-initialized "guard zones" before and after each
allocated area, and check their content at free() (and
at some other times) to determine whether the program has
stomped outside its supposed allocation. The sizes of
the guard zones must, obviously, depend on the alignment
required for the payload; I've just hard-wired this with
a #define, but it would be nicer if there were a clean
way to get the result.
Summary: The answer to the alignment question would be useful
in some specialized circumstances, but might not be useful enough
to justify all the work a Standards committee might have to expend
on it. Note in particular that making use of the answer involves
doing arithmetic on integer representations of pointer values,
which means the committee would have to come up with definitions
for how to convert back and forth; the current definitions are
not strong enough to support the uses we're considering.
--
Er*********@sun .com