mo@uunet.UU.NET (Mike O'Dell) (05/05/88)
Alignment issues in C are actually quite simple, and could actually be solved quite nicely in good ol' Version 6 C, long before some of the more recent "improvements." This claim specifically applies to C implementations of word-oriented machines as well as byte-oriented ones. There are actually two issues to consider: one is resolution - how many bits it takes to address an object, and alignment - what is the most restrictive alignment required for addressing objects. The C type with the greatest resolution is char * pure and simple. "char" is the smallest addressable object in the language, and therefore takes the most number of bits to address. This is most obvious in the word-addressed case where you must carry extra bits beyond the basic address to get what you need. On most real computers (but not IBM-PCs), double-precision floats are usually the most highly aligned type, making double * the most stringently-aligned type. This means that the ANSI type void * should represent like char * but align like double * Usually, these are the maximal requirements for a value returned from malloc(), and hence, void *malloc() is considered a completely correct statement of truth. The problem which comes quickly to mind, however, is that on Intel 8[012]86 machines, the screwiness of the addressing architecture makes it mandatory in all but one or two memory models for malloc() to return an object with 16-byte ("paragraph") alignment. Since void * doesn't necessarily do that, it is an incomplete semantic definition to simply declare void *malloc() The claim made by that statement is true: the pointer returned will have sufficient resolution to address (char *) and will be at least as stringently aligned as (double *), but alas that isn't the entire story. In some sense, it boils down to what you want a declaration to say. Do you want a declaration to be a minimum requirement, or a maximum requirement? void *malloc() is certainly satisfied by what the function returns, and is quite useful for most cases, but when IMPLEMENTING malloc(), you better damn well understand a great deal about the machine and how pointers really get used in the code generated by a particular compiler. So, if we dismiss malloc() (and memory allocation in general) as a terribly machine-dependent intrinsicly-unportable function, which I think it must be, since it explicitly deals with representations, then it comes down to whether you believe a particular declaration is making a statement of some minimal requirement met, or is making a promise about some other issue such as alignment. And if it weren't for the necessity to make two different promises at once (I promise to use enough bits to get at a char, but I won't ever return anything which really really has any of those bits set!), (void *) isn't really needed. But it seems to be. Yours for clearer confusion, -Mike O'Dell