flaps@utcs.UUCP (06/29/86)
How about an #include <align.h> which contains a single #define which gives the alignment constant for this machine? This of course would only be useful if put into the standard. Which reminds me, is sizeof(char) always = 1 yet? I mean, is it guaranteed? ajr
gwyn@brl-smoke.ARPA (Doug Gwyn ) (06/30/86)
In article <1986Jun29.15:39:38.4762@utcs.uucp> flaps@utcs.uucp (Alan J Rosenthal) writes: >Which reminds me, is sizeof(char) always = 1 yet? I mean, is it guaranteed? sizeof(char) is indeed supposed to be 1 as things now stand. However, this may need to be reconsidered. The meaning of "char" is currently overloaded, which doesn't much matter until one gets into multi-byte character representations. I'm hoping to work up a complete discussion and a number of specific proposals in a paper for X3J11 as soon as I can find the time.
levy@ttrdc.UUCP (Daniel R. Levy) (07/06/86)
In article 38.4762@utcs.uucp>, flaps@utcs.UUCP writes: >How about an #include <align.h> which contains a single #define which gives the >alignment constant for this machine? >This of course would only be useful if put into the standard. >Which reminds me, is sizeof(char) always = 1 yet? I mean, is it guaranteed? >ajr Say if ajr's suggestion were implemented and /usr/include/align.h contained something like #define ALIGNSIZE 4 /* long int */ Now, given an arbitrary char* pointer, how do we tell if it is aligned? Now on a machine with four-byte pointers and unsigned longs, we could do: char *c; ... if (((unsigned long)c % ALIGNSIZE) == 0) { /* c is aligned */ ... } else { /* c is not aligned */ ... } But... what about a machine where alignments are "screwy," for example they wanted doubles to be located at some fixed offset, say 2, from addresses which are integral multiples of 4 or 8? I can think of no such machine (indeed I believe design of such would be an exercise in masochism) but where is it engraved in stone what "aligned" really means (which we presume must imply some guarantee of solid mapping between pointers and some other data type, usually long... I used unsigned long in my example because it would work on a machine with one's complement arithmetic and pointers with their MSB set, whereas a bit-pattern copy to a long would produce a number which could not be reliably tested for alignment--but again we hope that the mapping instruction would be smarter than a bit-pattern copy). -- ------------------------------- Disclaimer: The views contained herein are | dan levy | yvel nad | my own and are not at all those of my em- | an engihacker @ | ployer or the administrator of any computer | at&t computer systems division | upon which I may hack. | skokie, illinois | -------------------------------- Path: ..!{akgua,homxb,ihnp4,ltuxa,mvuxa, vax135}!ttrdc!ttrda!levy
flaps@utcs.UUCP (07/09/86)
In article <1038@ttrdc.UUCP> levy@ttrdc.UUCP (Daniel R. Levy) writes: >Say if ajr's suggestion were implemented and /usr/include/align.h contained >something like > >#define ALIGNSIZE 4 /* long int */ > >Now, given an arbitrary char* pointer, how do we tell if it is aligned? [provides the simple case] >But... what about a machine where alignments are "screwy," for example they >wanted doubles to be located at some fixed offset, say 2, from addresses which >are integral multiples of 4 or 8? #define OFFSET 2 #define ISALIGNED(p)((p)%4 == 2) or of course in the usual case: #define ALIGNSIZE 4 #define OFFSET 0 #define ISALIGNED(p)((p)%4 == 0) Of course this could be expanded for any other information that a user needed to know about the alignment. And since it would all be in an include file, it would not break any existing programs, and is not truly an addition to the language. I think it would be good to put it in the standard. ajr
aglew@ccvaxa.UUCP (07/09/86)
An alignment constant would not necessarily work, because there are machines that have unusual alignment restrictions. My favorite is `strictly aligned power of two sized' - ie. an object of size N must be aligned on a boundary of 2^ceil(lg(N)), if indexing is to be used to access fields of such an object. Note that malloc(nitems*sizeof(obj)) is conservative for such a beast, assuming sizeof rounds up correctly, but calloc() can be a bit more intelligent. This scheme is strictly size dependent, but screwier schemes are possible. Since an alignment constant doesn't necessarily work, how about an alignmentof(object) operator, analagous to sizeof()? At least that'll work on all architectures that have alignments based on multiples. Andy "Krazy" Glew. Gould CSD-Urbana. USEnet: ihnp4!uiucdcs!ccvaxa!aglew 1101 E. University, Urbana, IL 61801 ARPAnet: aglew@gswd-vms
rbutterworth@watmath.UUCP (Ray Butterworth) (07/11/86)
> Since an alignment constant doesn't necessarily work, how about an > alignmentof(object) operator, analagous to sizeof()? At least that'll work > on all architectures that have alignments based on multiples. An "alignof(type)" operator is already required by X3J11 (although they don't seem to have realized this yet) in order to implement their va_arg(ap,type) macro.
chris@umcp-cs.UUCP (07/12/86)
In article <2600066@ccvaxa> aglew@ccvaxa.UUCP writes: >Since an alignment constant doesn't necessarily work, how about an >alignmentof(object) operator, analagous to sizeof()? At least that'll work >on all architectures that have alignments based on multiples. I think this can still be implemented with a common header file, e.g., #define OFFSET_TO_ALIGN(ptr) /*something*/ #define IS_ALIGNED(ptr) (OFFSET_TO_ALIGN(ptr) == 0) On a Vax, and purely for efficiency, /*something*/ is #define OFFSET_TO_ALIGN(ptr) ((4 - (int) (ptr)) & 3) On a Pyramid, the same `define' works; on a Sun, it can be reduced to #define OFFSET_TO_ALIGN(ptr) ((int) (ptr) & 1) On your hypothetical machine, /*something*/ may be #define OFFSET_TO_ALIGN(ptr) (_offset_to_align(sizeof *(ptr))) where _offset_to_align is a library function. (N.B.: That it *can* be done this way does not mean that it *must* be done this way.) -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1516) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@mimsy.umd.edu
gwyn@BRL.ARPA (07/12/86)
You say that an alignof(type) operator is required in order to implement the va_arg(ap,type) macro. Could you please demonstrate this? I don't believe it.
aglew@ccvaxa.UUCP (07/13/86)
... > Chris Torek responds to my alignof() proposal (the shorter name is ... > better): >I think this can still be implemented with a common header file, e.g., > > #define OFFSET_TO_ALIGN(ptr) /*something*/ > #define IS_ALIGNED(ptr) (OFFSET_TO_ALIGN(ptr) == 0) > >On your hypothetical [strictly aligned, power of two sized] >machine, /*something*/ may be > > #define OFFSET_TO_ALIGN(ptr) (_offset_to_align(sizeof *(ptr))) > >where _offset_to_align is a library function. He's right - I don't care if something gets stuck in the language or in a header file - but his macros have some weaknesses. (1) They can only be used to determine if a pointer is correctly aligned, not to generate a correctly aligned pointer. Ie. given an arena from which your malloc() draws stuff, do you run through every hole looking for IS_ALIGNED(p) where p is what you're allocating now? And what if you have a block beginning on a misaligned address - do you run through every byte in the block looking for a place to start? (2) On my hypothetical, strictly aligned, power of two sized, machine using sizeof as the sole criterion can lead to some inefficiencies. For example, a character string of length 2n+1 need not be allocated on a 4n boundary, if you know that indexing is never used into the string, or if you are willing to have indexing be slow (through explicit pointer calculations) when it is. So you don't need to waste those 2n-1 bytes. However, since the fields of a structure of size 2n+1 are very frequently indexed, then you are willing to waste the memory. --- The discussion is useful, though. We can see two needs: [A] a predicate IS_ALIGNED(ptr,type) which returns true or false if the ptr is correctly aligned for an object of type. The predicate can handle any machine's alignment restrictions, including multiple plus an offset type constraints (not my idea). On most machines it can be implemented by a macro in a header, something like #define IS_ALIGNED(ptr,type) ( sizeof(type) == 1 ? 1 \ : sizeof(type) == 2 ? ptr & 1 \ : ... \ : !(ptr & ((1<<(ALIGN-1))-1)) ) but Ooops! note that even on a VAX struct {char a,b;} doesn't HAVE to be aligned like this. [B] Constants that can be used in writing nearly machine independent memory allocators. For a large class of machines this can most simply be done by providing the sizeof() the largest data type that has alignment restrictions, eg. #define ALIGN sizeof(double) However, that doesn't cover my favorite architecture, strictly aligned power of two sized; but a macro generating the alignment constant can handle all architectures with alignment constraints based on multiples without offsets #define ALIGN(type) (1<<ceil_log(sizeof(type)) where ceil_log would have to be a function executable by the preprocessor. Of course, you can say "why bother going that extra little step just for one of Krazy Glew's hypothetical architectures..." Well (1) Even on conventional machines that have a single upper bound on alignment restrictions, ALIGN(type) might permit more efficient memory allocators, particularly if the upper bound on alignments is large. It may only be a 64 bit double now, but it is quite reasonable to see it becoming 128 bits extended precision floating point numbers, or even 256 bits, in the near future. (2) Such an architecture may not be hypothetical much longer... I hope, and I have reasons for hoping. (3) Such an architecture already exists! Surprised? I've heard of somebody who modified a 68000 compiler to use shifting and oring instead of mutiplying and adding to access fields of structures. Hai presto! a strictly aligned power of two sized system. And it ran faster than conventional code. Since memory keeps getting cheaper... Andy "Krazy" Glew. Gould CSD-Urbana. USEnet: ihnp4!uiucdcs!ccvaxa!aglew 1101 E. University, Urbana, IL 61801 ARPAnet: aglew@gswd-vms
rbutterworth%watmath.waterloo.edu@CSNET-RELAY.ARPA (07/14/86)
> From seismo!BRL.ARPA!gwyn Sat Jul 12 05:07:56 1986 > You say that an alignof(type) operator is required in order to > implement the va_arg(ap,type) macro. Could you please demonstrate > this? I don't believe it. Suppose we have a machine where sizeof(double)==8, sizeof(long)=8, sizeof(int)==4, alignof(double)==8, alignof(long)=4 alignof(int)==4. What does the macro va_arg(list,long) expand to? The token "long" can't be concatenated to form a predefined token such as "align_long" since it could just as easily have been "char *". So the only information we can really determine about the argument is by using sizeof(long). But this is simply 4 in this case. We still don't know where on the stack the argument will be. If it is a long (which we can't determine) it is at the next 4-byte boundary, but if it is a double (which it could just as easily be, given only its size) it is at the next 8-byte boundary. How is va_arg supposed to differentiate between these two cases? I didn't see anything in the standard restricting how things must be passed in the stack (e.g. all arguments must be aligned the same way (as in VAX BSD)). If there isn't an alignof() operator, some other built-in would be needed (e.g. newptr=align(oldptr,type)). Another example would be the case of structures. There is nothing that says that "struct{char a; char b;}" has to be aligned the same as "struct{double c;}", and I certainly don't see any way of making va_arg determine the alignment without a built-in alignof() operator. With a very strict reading of the standard one might decide that the "..." arguments can only be of type int, unsigned int, or double. That would certainly make my above examples invalid, but it would also make <stdarg.h> much less useful. If so, the standard could make this much clearer by changing The parameter _^Ht_^Hy_^Hp_^He is a type name such that the type of a pointer to an object that has the specified type can be obtained simply by postfixing a * to the type name. to The parameter _^Ht_^Hy_^Hp_^He must be "int", "unsigned int" or "double". or better yet, by replacing va_arg by three macros, va_int, va_unsigned, and va_double. I really don't think this was what was intended though.
gwyn@BRL.ARPA (07/14/86)
Who says stack alignment has to be the same as machine-forced alignment? It's certainly not on some of the machines I use. Since the parameter stack can have different alignment constraints, one would actually need a stkalignof operator for <stdarg.h>, but it would be of use only for this one purpose and therefore should not be intruded upon the programmer's notice. It's true that it would be easier to implement <stdarg.h> on some machines if the alignof operator were available, but it's not required. Indeed, since the compiler can tell that variable- parameter functions are involved, it may choose to use what we old-timers call "dope vectors" to describe the variable args. On some unusual architectures, actual library functions may have to be used in the implementation of va_arg() (which itself is a macro). There was a motion last meeting to drop parmN, but it was defeated; however, we decided to make "register" parmN an undefined situation. Although I can't recall anything that requires all structs to be aligned as stringently as the worst possible scalar data type, implementations may elect to do so, or to make special arrangements so that the size and alignment of very small structs are convenient for <stdarg.h> (besides having to include padding so that arrays of structs work out right). The reference in the draft standard to int, unsigned int, and double was with respect to possible result of parameter widening promotions; it wasn't meant to rule out other parameter types.