gjo@calmasd.GE.COM (Glenn Olander) (01/23/88)
Please forgive a possibly neophyte-type question, but is it true that there may be an inherent incompatibility between RISC and conventional machines? In particular, I believe that many RISC machines require data to be aligned on a natural boundary, e.g. longwords must be referenced on a 4-byte boundary. This requires compilers to make accomodations to ensure that such alignment always occurs, even if it means padding a data structure which contains mixed types of data, for example a C structure with a mixture of shorts, longs, and doubles. If this is true, then it would seem to also be true that a C structure could have different lengths, depending on whether it was compiled on a RISC or non-RISC machine. Further, it would seem that if that C structure were written out to a file, it could only be read properly by a machine of the same type as that which wrote it. Does such incompatibilty truly exist? If I create a file on a Sun/4 will I be able to read it on a Sun/3? Glenn Olander GE Calma gjo%calmasd.ge.com@sdcsvax.ucsd.edu
schwartz@gondor.cs.psu.edu (Scott E. Schwartz) (01/24/88)
In article <2635@calmasd.GE.COM> gjo@calmasd.UUCP (Glenn Olander) writes: >machines? In particular, I believe that many RISC machines require data >to be aligned on a natural boundary, e.g. longwords must be referenced >on a 4-byte boundary. This is true of sparc. >If this is true, then it would seem to also be true that a C structure >could have different lengths, depending on whether it was compiled >on a RISC or non-RISC machine. Further, it would seem that >if that C structure were written out to a file, it could only be read >properly by a machine of the same type as that which wrote it. This is exactly correct. >Does such incompatibilty truly exist? If I create a file on a Sun/4 >will I be able to read it on a Sun/3? From "Porting Software to SPARC", Sun part no. 800-1596-10, Nov '87, p4: Because of the three considerations above, members of a given structure may have different offsets on SPARC machines than on the MC680x0, and the structure as a whole may have a different size. Even though data representations identical on the MC680x0 and the SPARC, binary files where raw structures have been written out may not be portable between processors. -- Scott Schwartz schwartz@gondor.cs.psu.edu
mash@mips.UUCP (01/24/88)
In article <2635@calmasd.GE.COM> gjo@calmasd.UUCP (Glenn Olander) writes: >Please forgive a possibly neophyte-type question, but is it true that >there may be an inherent incompatibility between RISC and conventional >machines? In particular, I believe that many RISC machines require data >to be aligned on a natural boundary, e.g. longwords must be referenced >on a 4-byte boundary. This requires compilers to make accomodations to >ensure that such alignment always occurs, even if it means padding a >data structure which contains mixed types of data.... >If this is true, then it would seem to also be true that a C structure >could have different lengths, depending on whether it was compiled >on a RISC or non-RISC machine. Further, it would seem that >if that C structure were written out to a file, it could only be read >properly by a machine of the same type as that which wrote it. >Does such incompatibilty truly exist? If I create a file on a Sun/4 >will I be able to read it on a Sun/3? This issue is not inherent to RISC versus non-RISC machines. Here are the implementation choices: Machine: M1: require alignment for every object SPARC, 78000, most other RISCs WE32xxx, Clipper M1A: alignment required, except practical unaligned code MIPS R2000 (odd-case - see later) M2: no alignment required IBM 370, VAX, MC68020, NSC32xxx, Intel 80X86 M3: alignment required for some, but not others MC68000 (16-bit on 16-bit boundary, 32 on 16-bit also) C language choices: C1: align every piece of data on its natural boundary, padding as necessary, including padding the size of a structure to the maximum alignment requirement of anything found in that structure [this makes arrays of structures work]. C2: Align some things, but not others (there might have been a C3: align nothing, but I couldn't think of a C compiler that does it) It's fairly clear that: 1) C1 (align everything) is the safest choice. 2) All of the M1 machines want C1 alignment Here's the matrix, with some examples: M1 M2 M3 C1 All M1s VAX 4.3BSD R2000 68020-? 68010-? C2 - Sun-68020 Sun-68010 Some vendors (Convergent, at least, unless memory fails me), implemented C1 even on 68010s that didn't require it. Sun aligned 32s on 16s on 68000s and stayed that way on 68020s, but Sun-4s indeed require 32 on 32. Thus, structures exist that do not have the same mapping between Sun-3s and Sun-4s. Fortunately, most C compilers chose C1 alignment, and most structures were often padded by hand by people who knew that unaligned things cost cycles on almost any machine. Case M1A is a little odd: the MIPS R2000 requires alignment of things on natural boundaries; however, "unaligned" load/store instruction pairs are provided, which can be used either from assembler, or (soon) with compiler switches to make the compielr use them when alignment is in doubt. Thus, loading something where you're not sure takes the 2 cycles that are required on most systems for something that is truly unaligned, and storing is likewise. Besides string-manipulation, and some COBOL-related things, a major motivation of of this is: The more serious issue here, actually, is there is a class of program that is excruciatingly difficult to port for pure M1-class machines. Specifically, some large FORTRAN programs (as old CAD systems), often in the half-million-line-plus category contain COMMON+EQUIVALENCE combinations THAT CANNOT EVER BE ALIGNED UNTIL THE CODE IS HEAVILY REWORKED. In particular, IBM-derived programs with INTEGER*2 in them can be nasty. For some reason, some owners have such code (thru which the armies have marched thru the years) have proved to be less than excited about porting it... -- -john mashey DISCLAIMER: <generic disclaimer, I speak for me only, etc> UUCP: {ames,decwrl,prls,pyramid}!mips!mash OR mash@mips.com DDD: 408-991-0253 or 408-720-1700, x253 USPS: MIPS Computer Systems, 930 E. Arques, Sunnyvale, CA 94086
guy@gorodish.Sun.COM (Guy Harris) (01/24/88)
> >If this is true, then it would seem to also be true that a C structure > >could have different lengths, depending on whether it was compiled > >on a RISC or non-RISC machine. True, but not necessarily for reasons having to do with RISC vs. non-RISC: 1) I know of one CISC that requires 4-byte alignment of 4-byte quantities, and 2-byte alignment of 2-byte quantities: the WE32100. 2) While the VAX does not impose any alignment restrictions, I think most, if not all, VAX implementations run faster if 4-byte quantities are aligned on 4-byte boundaries and 2-byte quantities are aligned on 2-byte boundaries. As such, both the VAX UNIX C compiler and the WE32K C compiler, and probably the VAX/VMS C compiler, align 4-byte quantities in structures on 4-byte boundaries and 2-byte quantities in structures on 2-byte boundaries. The structure as a whole is aligned on the boundary required by its most strictly aligned member. These are the same rules used by the SPARC C compiler; however, on the SPARC *8*-byte quantities (e.g., double-precision floating point numbers) must be aligned on *8*-byte boundaries. These restrictions are not imposed by e.g. the WE32K nor the VAX, so they only align them on 4-byte boundaries. However, there are machines with different alignment restrictions, and C compilers with different alignment rules: 1) The MC68010 requires 2-byte quantities to be aligned on 2-byte boundaries, but does not require 4-byte quantities to be aligned on 4-byte boundaries. Most of the C compilers for UNIX 68K implementations put 4-byte quantites only on 2-byte boundaries, and always align structures on 2-byte boundaries even if no member requires this alignment. These rules are often propagated to the 68020, which imposes no alignment restrictions. 2) The CCI Power 6/32 C compiler, last time I dealt with it, always aligns structures on at least 4-byte boundaries. > >Further, it would seem that if that C structure were written out to a file, > >it could only be read properly by a machine of the same type as that which > >wrote it. > > This is exactly correct. And not only that, it would still be true even if all C implementations imposed the exact same alignment rules! VAXes, National Semiconductor 32Ks, and Intel 80*86es address the bytes within a 2-byte or 4-byte quantity from bottom to top; the least significant byte is byte 0. These architectures are called "little-endian". IBM 360/370s, Motorola 68Ks, AT&T WE32Ks (except for the WE32000), SPARCs, and CCI Power 6/32s address them from top to bottom; the *most* significant byte is byte 0. These architectures are called "big-endian". The WE32000, and, if I remember correctly, the MIPS chips, can select which byte order to use, although I think all WE32000 implementations use the "big-endian" byte order. Tapes, disks, and networks are usually byte-serial. They generally do not record (in the case of tapes and disks) or transmit (in the case of networks) 2-byte or 4-byte quantities in parallel. This means that a sequence of *bytes* will, when copied via tape or disk or transmitted over a network, from a big-endian to a little-endian machine, appear the same. If you put the character string "hi mom" on the tape, disk, or wire, and send it to a machine with the opposite byte sex, that machine will see "hi mom" (assuming, of course, that the hardware and/or software on both ends uses the same character set). However, if you put the number 127 on the tape, disk, or wire as a 4-byte integer, and send it between two machines with different byte sexes, the number will appear to be 2130706432 on the other machine. A machine will generally write a 4-byte integer on tape or disk or send it over the wire by putting the byte with address 0, then the byte with address 1, then 2, then 3. This means that a little-endian machine will put out a byte with the value 127, and then 3 bytes with the value 0. A big-endian machine will put out 3 bytes with the value and then a byte with the value 127. A machine with the opposite byte sex will put the 127 in the *most*-significant byte of the integer and put the zeroes in the lower three bytes. Furthermore, floating-point formats differ in ways other than their byte order. Most of the architectures listed above use the IEEE floating-point format (either directly or in their floating-point coprocessors); however, neither the IBM 360/370 nor the VAX do, and I don't think the Power 6/32 does either. And, on top of that, the size of the C data types are not guaranteed to be the same. "int" is generally 4 bytes on the 360/370, VAX, the NS32K, WE32K, SPARC, and MIPS architectures. It may be 2 or 4 bytes on the 80*86 and Motorola 68K architectures, depending on the implementation. It may be *8* bytes on a supercomputer. It may be *3* bytes on a 24-bit machine. On top of this, there's not even a guarantee that a byte is 8 bits, or that an "int" is 16 or 32 bits; there exists at least two C implementations on 32-bit machines, one of which even runs UNIX. In short, the statement made by Scott Schwartz in the summary line: you had better use XDR or something similar is 10,000% true, as is the statement in the original article: Further, it would seem that if that C structure were written out to a file, it could only be read properly by a machine of the same type as that which wrote it. There are exceptions to this statement: a structure written out on an Intel 386-based machine *might* be readable directly on a NS32K-based machine, for instance - althought I don't know that their alignment rules or floating-point formats are the same (both are, I think, IEEE, but I don't know that the byte order in *floating*-point numbers is the same). These exceptions are rare, and as indicated I don't even know which of them really exist. If you want to write data to a file or put it out on the network so that some other machine of a different type can read it, *don't* just dump a raw structure; use the Sun XDR library, or roll your own routines that put things out in a standard byte order with a standard floating point format, standard alignment, standard data sizes, etc., etc.. And as for the particular question: > >Does such incompatibilty truly exist? If I create a file on a Sun/4 > >will I be able to read it on a Sun/3? As Mr. Schwartz has already pointed out, the answer is "yes". The Sun-3 uses the MC68020 chip, and uses the alignment rules that most 68K UNIX C implementations use: structures are always aligned on at least a 2-byte boundary, and most quantities are only aligned on 2-byte boundaries. The Sun-4 uses the SPARC chip, and uses the rules listed above for that chip: structures may be aligned on 1-byte boundaries if they contain nothing requiring a stricter alignment, 4-byte quantities are aligned on 4-byte boundaries, and 8-byte quantities are aligned on 8-byte boundaries. Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com
csg@pyramid.pyramid.com (Carl S. Gutekunst) (01/24/88)
In article <2635@calmasd.GE.COM> gjo@calmasd.UUCP (Glenn Olander) writes: >I believe that many RISC machines require data to be aligned on a natural >boundary, e.g. longwords must be referenced on a 4-byte boundary. While this is true of practically all RISC and RISC-like designs, it is also true of nearly all other architectures, too. The number of architectures that allow totally random positioning of objects is quite small, and I daresay that C programmers have gotten totally spoiled by them. (I did not say installed base! Number of *architectures.* That means the VAX counts as 1.) >...then it would seem to also be true that a C structure could have different >lengths, depending on whether it was compiled on a RISC or non-RISC machine. >...if that C structure were written out to a file, it could only be read >properly by a machine of the same type as that which wrote it. C structures compiled on *any* two different architectures are likely to be different lengths. Think of all the things that can be different besides the alignment: 16 or 32 bit ints, size of floats, format of floats. Then add byte order if you really want to confuse things. >If I create a file on a Sun/4 will I be able to read it on a Sun/3? Under the terms you described, no. Binary data files are simply not portable. So use ASCII text files. <csg>
ok@quintus.UUCP (Richard A. O'Keefe) (01/25/88)
In article <2635@calmasd.GE.COM>, gjo@calmasd.GE.COM (Glenn Olander) asks about data alignment in RISCs and is worried that > If this is true, then it would seem to also be true that a C structure > could have different lengths, depending on whether it was compiled > on a RISC or non-RISC machine. Further, it would seem that > if that C structure were written out to a file, it could only be read > properly by a machine of the same type as that which wrote it. Yes, both of these problems exist. But 68010s require 16-bit alignment for 16-bit and 32-bit data, whereas 68020s do not, so the problem may exist even within a processor family. (The same is true of IBM's mainframes: the old models had stricter alignment requirements.) Even on a single machine, there is no reason to expect two compilers to lay structures out the same way. There is even one machine where the byte sex is determined at powerup (if I've read the manuals properly), so a data file might written by one program might not be readable by another, even though both used the same compiler and the same #include file. Then of course there are floating-point differences... This isn't really a C problem, either. The problem exists in any language having records. Also, even on machines which don't require 32-bit alignment, there may be a substantial speed advantage in aligning the data anyway. (We've seen figure of 30% for C-coded examples.) So a compiler may well align things for speed. There are two solutions: write data files as text, or use XDR.
aglew@ccvaxa.UUCP (01/26/88)
Further, it would seem that if that C structure were written out to a file, it could only be read properly by a machine of the same type as that which wrote it. Many have affirmed the veracity of this statement. May I amplify it: it sometimes isn't true between machines of the same type. A while back I worked on a MULTIBUS 68000 system that did byte swapping to match the 68000's idea of data layout. Of course, it couldn't interchange disk data with VME 68000 systems without byte swapping.
daveh@cbmvax.UUCP (Dave Haynie) (01/26/88)
in article <2635@calmasd.GE.COM>, gjo@calmasd.GE.COM (Glenn Olander) says: > Please forgive a possibly neophyte-type question, but is it true that > there may be an inherent incompatibility between RISC and conventional > machines? In particular, I believe that many RISC machines require data > to be aligned on a natural boundary, e.g. longwords must be referenced > on a 4-byte boundary. This requires compilers to make accomodations to > ensure that such alignment always occurs, even if it means padding a > data structure which contains mixed types of data, for example a C > structure with a mixture of shorts, longs, and doubles. This is already going on in some degree with non-RISC machines. For the 68000, for instance, short and long words must be accessed on word boundaries. The 68020 doesn't have this requirement, but it'll perform much faster if words are on word boundaries and longwords are on 4-byte boundaries. For at least the Lattice compiler I use (V4.0, Amiga OS), the compiler is normally using word alignment for non-byte objects, but has a switch to force longword alignment. I'm sure all 32 bit processors get a speed advantage with longword aligned items, it's just a matter of whether it's a requirement or not. With RISC type machines, such alignment being a requirement would certainly be in keeping with RISC's goal of hardware simplicity. > If this is true, then it would seem to also be true that a C structure > could have different lengths, depending on whether it was compiled > on a RISC or non-RISC machine. You'll already find these issues in going between non-RISC machines. So you should expect that they may show up in RISC vs. non-RISC. > Further, it would seem that > if that C structure were written out to a file, it could only be read > properly by a machine of the same type as that which wrote it. In many cases. This is especially true when going between machines with different CPU families. The file I write directly on my Amiga won't be directly readable on a VAX or an IBM PC, due to byte ordering as well as word alignment. It would probably be readable on a Macintosh or a Sun/3, providing their compilers make similar assumptions on data alignments. > Glenn Olander > GE Calma > gjo%calmasd.ge.com@sdcsvax.ucsd.edu -- Dave Haynie "The B2000 Guy" Commodore-Amiga "The Crew That Never Rests" {ihnp4|uunet|rutgers}!cbmvax!daveh PLINK: D-DAVE H BIX: hazy "I can't relax, 'cause I'm a Boinger!"
klein@ridge.UUCP (Doug Klein) (01/28/88)
In article <3195@cbmvax.UUCP>, daveh@cbmvax.UUCP (Dave Haynie) writes: > in article <2635@calmasd.GE.COM>, gjo@calmasd.GE.COM (Glenn Olander) says: > > > Please forgive a possibly neophyte-type question, but is it true that > > there may be an inherent incompatibility between RISC and conventional > > machines? > > > If this is true, then it would seem to also be true that a C structure > > could have different lengths, depending on whether it was compiled > > on a RISC or non-RISC machine. > Having spent the last four years porting large applications to a data aligned machine (Ridge), I would warn you of more than just data file compatibility! This is potentially the least of your problems. To mention a few of the gotcha's I have run into: FORTRAN example 1) Programmer decides he needs a "array copy" routine. For whatever reason he decides that the fastest way to copy data is to use: subroutine copy(a,b,count) double precision a(1),b(1) integer count do i=1,count b(i) = a(1) enddo return end Now he calls it from somewhere as: integer x(100),y(100) ... call copy(x,y,100) The problem is that x and y are *potentially* word aligned, but the subroutine 'copy' uses double loads and stores! BLAM - alignment trap! The scary part of this is the the alignment of x and/or y can be effected in a part of the program *very* far away, e.g., a common block thousands of lines away. The other scary part is it may take many, many sample input sets to hit this case. FORTRAN example 2) I've seen older FORTRAN programs that try to do forms of stack manipulation by allocating a large array, (real buffer(100000) comes to mind), and then poking arbitrary structures into arbitrary places in these arrays - lots of potential alignment problems here! This happens frequently with EQUIVALENCE statements. (In particular reference to the originator of this discussion, Calma's DDM is a nightmare for this problem). Fortunately, large C applications tend to have been developed with the idea of portability, and *usually* have run into alignment issues early in their development life. Warning flags should fly, though, when looking at code that runs only on VAXen or 68k boxes. Similar to FORTRAN example 2, a common practice in large C applications is to malloc a big chunk of space, and then start putting arbitrary structures in it. I've seen this in several of the large commercial rendering codes, which do a lot of their own "stack" manipulation. The workaround has usually been to put some "aligning" code into the low-level routines, i.e., look at the actual address mod'ed with 4 (or 8, or whatever), and then adjust appropriately. Casting something can cause the compiler to generate an instruction with strict alignment restraints when the object being cast is not aligned. (I haven't personally run into this many times). Doug Klein
johnw@astroatc.UUCP (John F. Wardale) (01/29/88)
In article <354@ridge.UUCP> klein@ridge.UUCP (Doug Klein) writes: >FORTRAN example 1) > >Programmer decides he needs a "array copy" routine. For whatever reason >he decides that the fastest way to copy data is to use: > > subroutine copy(a,b,count) > double precision a(1),b(1) > ... > >Now he calls it from somewhere as: > > integer x(100),y(100) > ... > call copy(x,y,100) Not only is this UNDEFINED by the Fortarn standard, the "accepted" assumetime in Fortran is sizeof(double) == 2*sizeof(int) == 2*sizeof(real) So, this will (possibly/probably) copy *TWICE* the span of X !!! The "Proper" way to do this is to have CCOPY, ICOPY, RCOPY, DCOPY, ZCOPY for CHARACTER, INTEGER, REAL, DOUBLEPRECISION, COMPLEX. This is why Ada added Generics and all the "overlaoding" stuff! > a common practice in large C applications >is to malloc a big chunk of space, and then start putting arbitrary >structures in it. .... >The workaround has usually been to put some "aligning" code into >the low-level routines, The BSD 4.3 malloc grabs memory by the page (at least page aligned) and manages pools of bocks for each power of 2 size. Thus these WILL be sufficently aligned!! I claim that any other maolloc where: p = (struct anything)malloc(xxx); or at least: p = (struct anything)malloc(sizeof(struct anything); can cause an error is a *SYSTEM* bug in *MALLOC* !!! -- John Wardale ... {seismo | harvard | ihnp4} ! {uwvax | cs.wisc.edu} ! astroatc!johnw To err is human, to really foul up world news requires the net!
gwu@clyde.ATT.COM (George Wu) (02/02/88)
Roy Smith posts: > In article <2635@calmasd.GE.COM> gjo@calmasd.UUCP (Glenn Olander) writes: > > it would seem that if that C structure were written out to a file, it could > > only be read properly by a machine of the same type as that which wrote it. > > Why is this a surprise? Lots of things prevent you from writing a > structure on one machine and reading it on another: byte (and bit) order, > padding requirements, word length, floating point formats, etc. If you > want to be able to have your file read by another machine type, you > shouldn't be writing binary structures. Use ascii, or hton(), or XDR, or > something like that. Okay, so what formats are used? I know X-Windows has some such convention to transmit binary data across the network, ie. a client and a server on different machines. What format do they use? (Hopefully, Roy will expand upon hton() and XDR. I think ASCII is self-explanatory.) I'm not sure what C-MU's Andrew system (consisting of Microvax-IIs, Sun-3s, Sun-2s, and mostly IBM RT/PCs) uses across the network, but for transportable files, a base 64 ASCII file is used. Any other bright ideas? George rutgers!clyde!gwu
aglew@ccvaxa.UUCP (02/04/88)
Talking about data structure alignment: I have often wanted an optimizing compiler that could take struct { long a; int b; long c; char d; } which is usually mapped into bytes as AAAABBxxCCCCDxxx (on a machine where misaligned accesses are penalized) and make it into AAAACCCCBBDx. Andy "Krazy" Glew. Gould CSD-Urbana. 1101 E. University, Urbana, IL 61801 aglew@gould.com - preferred, if you have nameserver aglew@gswd-vms.gould.com - if you don't aglew@gswd-vms.arpa - if you use DoD hosttable aglew%mycroft@gswd-vms.arpa - domains are supposed to make things easier? My opinions are my own, and are not the opinions of my employer, or any other organisation. I indicate my company only so that the reader may account for any possible bias I may have towards our products.
sjc@mips.COM (Steve "The" Correll) (02/05/88)
In article <28200092@ccvaxa>, aglew@ccvaxa.UUCP writes:
) I have often wanted an optimizing compiler that could take
) struct { long a; int b; long c; char d; }
) which is usually mapped into bytes as AAAABBxxCCCCDxxx
) (on a machine where misaligned accesses are penalized)
) and make it into AAAACCCCBBDx.
Note that you'd want to be able to select this optimization independently
of others, since it violates the Kernighan & Ritchie statement that the
addresses of fields increase from left to right, and a particular program
may or may not care about the violation.
--
...decwrl!mips!sjc Steve Correll
franka@mmintl.UUCP (Frank Adams) (02/09/88)
In article <28200092@ccvaxa> aglew@ccvaxa.UUCP (Andy "Krazy" Glew) writes: >I have often wanted an optimizing compiler that could take >struct { long a; int b; long c; char d; } >which is usually mapped into bytes as AAAABBxxCCCCDxxx >(on a machine where misaligned accesses are penalized) >and make it into AAAACCCCBBDx. How about AAAABBDxCCCC? This is what results if you follow the rule "put each component into the first suitable place for it". It has the important property that structures with the first few components identically defined will have those components in the same place. This is important -- the C++ translator relies on it, for example. Code that includes a size 1 (or size 0) array at the end of a structure to represent a variable-sized array may still be broken, however. -- Frank Adams ihnp4!philabs!pwa-b!mmintl!franka Ashton-Tate 52 Oakland Ave North E. Hartford, CT 06108
johng@ecrcvax.UUCP (John Gregor) (02/10/88)
In article <28200092@ccvaxa> aglew@ccvaxa.UUCP writes: > >I have often wanted an optimizing compiler that could take >struct { long a; int b; long c; char d; } >which is usually mapped into bytes as AAAABBxxCCCCDxxx >(on a machine where misaligned accesses are penalized) >and make it into AAAACCCCBBDx. > >Andy "Krazy" Glew. Gould CSD-Urbana. 1101 E. University, Urbana, IL 61801 I would like that also, but don't call it a struct. Rearranging the order breaks lots of code and violates K&R p. 196. Within a structure, the objects declared have addresses which increase as their declarations are read left-to-right. Call it a collection, or packed struct or something else. If I had a PCish type machine, I'd really like a feature like that. I'm spoiled rotten by virtual memory :-). -- pqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpq bdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbd John Gregor johng%ecrcvax.UUCP@germany.CSNET
jfc@athena.mit.edu (John F Carr) (02/18/88)
In article <496@ecrcvax.UUCP> johng@ecrcvax.UUCP (John Gregor) writes: >In article <28200092@ccvaxa> aglew@ccvaxa.UUCP writes: }}I have often wanted an optimizing compiler that could take }}struct { long a; int b; long c; char d; } }}which is usually mapped into bytes as AAAABBxxCCCCDxxx }}(on a machine where misaligned accesses are penalized) }}and make it into AAAACCCCBBDx. }I would like that also, but don't call it a struct. Rearranging the order }breaks lots of code and violates K&R p. 196. } } Within a structure, the objects declared have addresses } which increase as their declarations are read left-to-right. Isn't code which depends on allignment and spacing risky anyway? If a program assumes that for struct { int a; int b; } s; (&(s.a) - &(s.b)) == 1 it is making an unsupported assumption. Can someone post an example of a program which is portable and depends on the K&R rule quoted above? --John Carr (jfc@ATHENA.MIT.EDU)
alverson@decwrl.dec.com (Robert Alverson) (02/18/88)
In article <3001@bloom-beacon.MIT.EDU> jfc@athena.mit.edu (John F Carr) writes: > > (&(s.a) - &(s.b)) == 1 it is making an unsupported assumption. Can >someone post an example of a program which is portable and depends on >the K&R rule quoted above? How about this: typedef struct VarStr_str { int len; char str[1]; } VarStr; VarStr *MakStr(s) char *s; { VarStr *p = malloc(sizeof(VarStr) + strlen(s)); strcpy(p->str, s); return p; } This is a commonly used technique to avoid another memory indirection when accessing the variable data in the structure. Bob
bader+@andrew.cmu.edu (Miles Bader) (02/19/88)
jfc@athena.mit.edu (John F Carr) writes: > Isn't code which depends on allignment and spacing risky anyway? > If a program assumes that for > > struct { int a; > int b; > } s; > > (&(s.a) - &(s.b)) == 1 it is making an unsupported assumption. Can > someone post an example of a program which is portable and depends on > the K&R rule quoted above? The common case is that of extending the last element of a structure... Does anyone have code that will break if the elements are ordered arbitrarily, BUT the last element is kept last? -Miles
aglew@ccvaxa.UUCP (02/19/88)
..> K&R saying that struct fields must increase in address What does ANSI C, X3J11, say about this?
mcm@rti.UUCP (Mike Mitchell) (02/19/88)
I have written device drivers where I created a structure to hold
the memory-mapped status registers. Some of the hardware had very
strange memory alignments, and if the structure elements were changed,
the driver would break. For example, a structure to reference a serial
port might look something like:
struct ttport {
short t_tbaud; /* xmit baud rate */
char t_txt; /* transmitted character */
short t_rbaud; /* recv baud rate */
char t_rec; /* received character */
} *csr = 0xFF8000; /* address of device */
It would be more correct if a one byte pad were explicity put in after
the "char t_txt", but I think my point is still valid. There are some
cases where the order of the structure elements cannot be changed.
--
Mike Mitchell {decvax,seismo,ihnp4,philabs}!mcnc!rti!mcm mcm@rti.rti.org
"There's laughter where I used to see a tear. w (919) 541-6098
It's all done with mirrors, have no fear." h (919) 361-2048
hankd@pur-ee.UUCP (Hank Dietz) (02/19/88)
In article <286@bacchus.DEC.COM>, alverson@decwrl.dec.com (Robert Alverson) writes: > In article <3001@bloom-beacon.MIT.EDU> jfc@athena.mit.edu (John F Carr) writes: > > > > (&(s.a) - &(s.b)) == 1 it is making an unsupported assumption. Can > >someone post an example of a program which is portable and depends on > >the K&R rule quoted above? > > How about this: > > typedef struct VarStr_str { int len; char str[1]; } VarStr; > > VarStr *MakStr(s) char *s; { > VarStr *p = malloc(sizeof(VarStr) + strlen(s)); > strcpy(p->str, s); > return p; > } Portable? Try again. According to C, malloc does not exist -- it is just another user function. When you use malloc, you take advantage of a hole in the C type system (i.e., the very deliberate hole called type casting -- which you incidentally forgot in your use of malloc). I'm not saying the above hack isn't useful, but that your "struct" doesn't work as a struct. For example, C permits us to perform struct assignment, but you can't use it for a struct like yours because it will NOT COPY THE ELEMENTS WHICH WERE NOT DECLARED CORRECTLY -- i.e., it will copy only str[0] and not the whole string. The same is true of returning a struct or passing it by value. And sizeof is also wrong. You are trying to justify the need to maintain order of a struct's members by declaring something as a struct even though it can't be treated as one. Unfortunately, there is no way within C's type system to declare the above, so a kludge is needed. Compare your kludge to the Refined C concept of a paramtype (a parameterized struct type), which allows a variable-sized struct to be declared and treated as a first-class data object. (I can supply references and/or papers on Refined C if you're interested in how this works.) Aside from the above argument, it is possible for a compiler to determine when the order of members in a struct could be significant, and to rearrange only when the order can be changed without altering the program's meaning. For example, your struct only has to have the last field last... the order of the other fields doesn't matter. In code where the programmer may have sloppily used the struct address as the address of the first member, the compiler can constrain the first member to remain first. Of course, I'm not saying that it is easy to do, but just that a compiler can do it. (Minimizing space, or optimizing memory reference pattern, by cerfully rearranging struct members is something I have taught in fair detail in my graduate compilers courses for the past 4 or 5 years.) In summary, let's not try to encourage kludges as principles of language design. If you must write code which depends on the order, be aware that you are doing it outside of the language's type system, and that compilers will tend to generate lousy code for it because they have to make safe assumptions about what undecipherable (to the compiler) things you've done.
mac3n@babbage.acc.virginia.edu (Alex Colvin) (02/19/88)
Now that this discussion has moved from data alignment constraints in processors to alignment specifications in C, perhaps there's another newsgroup that's more appropriate.
aglew@ccvaxa.UUCP (02/20/88)
>It would be more correct if a one byte pad were explicity put in after >the "char t_txt", but I think my point is still valid. There are some >cases where the order of the structure elements cannot be changed. > >Mike Mitchell {decvax,seismo,ihnp4,philabs}!mcnc!rti!mcm mcm@rti.rti.org Agreed. I've written code that has to deal with hardware data structures like PTEs. Rearranging data structures is an optimization I would like to be able to turn on, but would definitely want to be able to turn off. And, yes, if the compiler guys can make the compiler automatically discover which those are, I'll use automatic generation - but until then I would like automatic control.
barmar@think.COM (Barry Margolin) (02/20/88)
In article <2047@rti.UUCP> mcm@rti.UUCP (Mike Mitchell) writes: >I have written device drivers where I created a structure to hold >the memory-mapped status registers. Some of the hardware had very >strange memory alignments, and if the structure elements were changed, >the driver would break. Such uses are inherently non-portable, so all that matters is whether the particular C compiler you are using provides a way to specify the order. Also, there is nothing in C that requires a particular alignment scheme, so a C compiler that aligned shorts at double-word boundaries would be within its rights, although it would screw up your example (all that the C spec specifies is that the addresses increase, but not by how much). > struct ttport { > short t_tbaud; /* xmit baud rate */ > char t_txt; /* transmitted character */ > short t_rbaud; /* recv baud rate */ > char t_rec; /* received character */ > } *csr = 0xFF8000; /* address of device */ And that assignment definitely isn't portable. Barry Margolin Thinking Machines Corp. barmar@think.com uunet!think!barmar
ok@quintus.UUCP (Richard A. O'Keefe) (02/20/88)
In article <20003@bu-cs.BU.EDU>, bzs@bu-cs.BU.EDU (Barry Shein) writes:
: Does anyone have any problems with:
: foo()
: {
: struct { double x; int i; } a;
:
: a.x = 3.1;
: a.i = 12;
: printf("%g %d\n",a);
: }
:
: as an example of a legal, portable program (printf isn't necessary,
: any function which takes multiple arguments possibly handed off as a
: struct)?
Unless I have completely misread the dpANS, this will not be legal
ANSI C, and the reason for that is that it has never been portable.
K&R say that elements of a structure are given increasing addresses
(a.x is lower than a.i), but the order of arguments is NOT defined:
printf() could easily expect its arguments in the opposite order. What
is more, some C compilers pass struct arguments on another stack; this
is common when "small" arguments are passed in registers. The Orion C
compiler, for example, allocated arrays and structs in one stack, and
scalars in another. (I got burned by this once; never again!)
amos@nsc.nsc.com (Amos Shapir NSTA) (02/21/88)
In article <2047@rti.UUCP> mcm@rti.UUCP (Mike Mitchell) writes: >I have written device drivers where I created a structure to hold >the memory-mapped status registers. Some of the hardware had very >strange memory alignments, and if the structure elements were changed, >the driver would break. This is not a very good example - the CPU reading the structure (i.e. the device controller) is not the same as the one you compile for, and therefore you cannot assume compatibility. It is true, though, that C is generally a what-you-see-is-what-you-get language, and most C programmers have come to expect - but this is more of a side-effect than a feature. -- Amos Shapir My other CPU is a NS32532 National Semiconductor 7C/266 1135 Kern st. Sunnyvale (408) 721-8161 amos@nsc.com till March 1, 88; Then back to amos%taux01@nsc.com
aglew@ccvaxa.UUCP (02/21/88)
>Does anyone have any problems with: > >foo() >{ > struct { > double x; > int i; > } a; > > a.x = 3.1; > a.i = 12; > printf("%g %d\n",a); >} > >as an example of a legal, portable program (printf isn't necessary, >any function which takes multiple arguments possibly handed off as a >struct)? Or does the receiving function have to strictly be declared >as receiving a like struct? (or is that just "a good idea" vs a true >restriction in the language?) > > -Barry Shein, Boston University Well, if this is portable I am really going to be surprised. Any language lawyers out there with a most recent X3J11? In my out of date copy, C.3.2.2 says something like "each argument is evaluated, and each formal parameter is assigned the value of the corresponding argument... If the number of arguments or their types after conversion do not agree with those of the formal parameters, the behavior is undefined". Of course, printf is variadic, "...", so type checking doesn't apply. Andy "Krazy" Glew. Gould CSD-Urbana. 1101 E. University, Urbana, IL 61801 aglew@gould.com - preferred, if you have nameserver aglew@gswd-vms.gould.com - if you don't aglew@gswd-vms.arpa - if you use DoD hosttable aglew%mycroft@gswd-vms.arpa - domains are supposed to make things easier? My opinions are my own, and are not the opinions of my employer, or any other organisation. I indicate my company only so that the reader may account for any possible bias I may have towards our products.
johng@ecrcvax.UUCP (John Gregor) (02/22/88)
In article <3001@bloom-beacon.MIT.EDU> jfc@athena.mit.edu (John F Carr) writes: >In article <496@ecrcvax.UUCP> johng@ecrcvax.UUCP (John Gregor) writes: >>In article <28200092@ccvaxa> aglew@ccvaxa.UUCP writes: >}}I have often wanted an optimizing compiler that could take >}}struct { long a; int b; long c; char d; } >}}which is usually mapped into bytes as AAAABBxxCCCCDxxx >}}(on a machine where misaligned accesses are penalized) >}}and make it into AAAACCCCBBDx. >}I would like that also, but don't call it a struct. Rearranging the order >}breaks lots of code and violates K&R p. 196. >Isn't code which depends on allignment and spacing risky anyway? >If a program assumes that for >struct { int a; > int b; > } s; > (&(s.a) - &(s.b)) == 1 it is making an unsupported assumption. Can >someone post an example of a program which is portable and depends on >the K&R rule quoted above? > --John Carr (jfc@ATHENA.MIT.EDU) That's not a good example of the type of code that would break. I use the ordering property of structs to hide data. If I have a struct which has some house keeping at the end of the struct, I don't have to tell the rest of the modules about it. e.g. struct private_foo_t { int a; short b; /* would be reordered to AAAACCCCBB */ int c; } fooba; struct public_foo_t { int a; short b; } foobr; By K&R I am guaranteed that: (&(fooba.b) - &(fooba.a)) == (&(foobr.b) - &(foobr.a)) /* i.e. the offsets are identical as long as the types ** are the same. */ This would break if structs were reordered. I believe that C++ uses this feature of C to implement its data hiding also. I do like the idea of an unordered aggregate type however. I've had to reorder structs for memory usage too many times and it's very machine dependent. -- pqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpq bdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbd John Gregor johng%ecrcvax.UUCP@germany.CSNET
aglew@ccvaxa.UUCP (02/25/88)
>That's not a good example of the type of code that would break. I use >the ordering property of structs to hide data. If I have a struct which >has some house keeping at the end of the struct, I don't have to tell >the rest of the modules about it. e.g. But K&R don't guarantee that struct { int; short; int; } will have fields in the same place as struct { int; short; } (or I'm sure that someone will give me chapter and verse), so this code isn't portable anyway.