ark@alice.UUCP (Andrew Koenig) (10/15/88)
In article <8810111934.AA21941@ucbarpa.Berkeley.EDU>, U23405@UICVM.Berkeley.EDU (Michael J. Steiner) writes: > Is it considered portable to do the following things with > structures or unions? > -pass them (by value) to functions Yes. > -have functions which return them Yes. > -assign them (=) Yes. > -test them (structures only) for equality with == No. -- --Andrew Koenig ark@europa.att.com
rkl1@hound.UUCP (K.LAUX) (10/17/88)
In article <8810111934.AA21941@ucbarpa.Berkeley.EDU>, U23405@UICVM.Berkeley.EDU (Michael J. Steiner) writes: > What I would like to know is (someone asked this before, I think): > > Is it considered portable to do the following things with > structures or unions? > -pass them (by value) to functions > -have functions which return them > -assign them (=) > -test them (structures only) for equality with == > > Thanks in advance, > > Michael Steiner > Email: U23405@UICVM.BITNET *Why* would you want to do this anyway? It is far easier to use pointers (and much more efficient). You should pass a *pointer* to the struct/union, declare functions as *returning a pointer* to the struct/union, as far as assignment goes, you want a copy of the contents of the struct and as for testing for equality, how can you assume that different compilers will evaluate them properly and exactly the same? If you are trying to get the compiler to automatically generate code to copy the fields of the structure, *don't*. What you can do is declare a pair of *unsigned char* pointers and cast the addresses of the source and destination structures to 'unsigned char', then do a short loop to copy byte by byte based on 'sizeof (struct)'. As for testing equality of the contents of two unions/structures,go through the effort of testing field by field - you can't go wrong this way. --rkl
mh@wlbr.EATON.COM (Mike Hoegeman) (10/17/88)
In article <8308@alice.UUCP> ark@alice.UUCP (Andrew Koenig) writes: >In article <8810111934.AA21941@ucbarpa.Berkeley.EDU>, U23405@UICVM.Berkeley.EDU (Michael J. Steiner) writes: >> Is it considered portable to do the following things with >> structures or unions? >> -pass them (by value) to functions >Yes. No >> -have functions which return them >Yes. No >> -assign them (=) >Yes. No I've worked on alot of machines where you cannot do ANY of the above. Maybe that's not "right". Maybe one should boycott such compilers. Any way you look at it though it's still not portable. I would avoid passing structures by value until more compilers allow this. Right now there are too many that don't.
wcs@skep2.ATT.COM (Bill.Stewart.[ho95c]) (10/19/88)
In article <8810111934.AA21941@ucbarpa.Berkeley.EDU> U23405@UICVM.Berkeley.EDU (Michael J. Steiner) writes: > Is it considered portable to do the following things with > structures or unions? There were a number of additions to the C language in about 1980, after the original K&R book, which almost everyone has adopted, even most compilers that call themselves "K&R". The main features were void, enums, and structure handling. Not everybody has them, but the following things are portable to any useful environment. > -pass them (by value) to functions Yes. > -have functions which return them Yes. Note that the mechanism for returning the value is implementation-defined. Some people put them on the stack; others may do arbitrarily strange things. > -assign them (=) Yes. > -test them (structures only) for equality with == No! The problem is that structures typically have holes in them caused by alignment requirements, and these holes have arbitrary junk in them. When you assign one structure to another, this junk is generally copied, but if you assign values member by member you aren't changing the junk in the holes, so equality comparisons don't work. -- #Bill Stewart, AT&T Bell Labs 2G218 Holmdel NJ 201-949-0705 ho95c.att.com!wcs # New Jersey Division of Motor Vehicles - # rising to a new level of incompetence
guy@auspex.UUCP (Guy Harris) (10/19/88)
> If you are trying to get the compiler to automatically generate code >to copy the fields of the structure, *don't*. What you can do is declare >a pair of *unsigned char* pointers and cast the addresses of the source and >destination structures to 'unsigned char', then do a short loop to copy byte >by byte based on 'sizeof (struct)'. Which may be slower than the code generated by the compiler to copy the structure.... Passing structures as arguments, returning them as function values, and assigning structure values to other structures is part of the C language specified by current ANSI C drafts (if it disappears in the final ANSI C standard, I'd be damn surprised). Some older compilers may not handle it, but most modern compilers should. (Note that there are compilers that support structure assignment but don't support "unsigned char"....) Even if you insist on not doing structure assignments, you may be better off using your C library's byte-copy routine, if it has one ("memcpy" or maybe "bcopy") than copying it yourself, byte by byte. "memcpy" and "bcopy" are usually optimized to run faster than a naive byte-by-byte copy. > As for testing equality of the contents of two unions/structures,go >through the effort of testing field by field - you can't go wrong this >way. Especially since few, if any, compilers implement testing equality of structures.
chip@ateng.ateng.com (Chip Salzenberg) (10/20/88)
According to mh@wlbr.EATON.COM (Mike Hoegeman): >I've worked on alot of machines where you cannot do ANY [structures in >assignment, as parameters and as function return values]. >Maybe that's not "right". Maybe one should boycott such compilers. Any >way you look at it though it's still not portable. This is a personal decision. Do you pander to every broken compiler? Or do you concentrate on making the best code that will be accepted by any correct compiler? To each his own. As for my opinion: If your compiler's broken, take it up with your vendor. -- Chip Salzenberg <chip@ateng.com> or <uunet!ateng!chip> A T Engineering Me? Speak for my company? Surely you jest! Beware of programmers carrying screwdrivers.
karl@haddock.ima.isc.com (Karl Heuer) (10/20/88)
In article <2685@hound.UUCP> rkl1@hound.UUCP (K.LAUX) writes: >[re struct copy] > *Why* would you want to do this anyway? It is far easier to use >pointers (and much more efficient). Whether it's easier depends on what you're trying to do. Whether it's more efficient depends on what you're doing and on how good the compiler is. (Quality implementations will return a small struct in the registers, as is already customary for builtin types.) Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
g-rh@XAIT.Xerox.COM (Richard Harter) (10/20/88)
In article <1988Oct19.192548.28438@ateng.ateng.com> chip@ateng.ateng.com (Chip Salzenberg) writes: >According to mh@wlbr.EATON.COM (Mike Hoegeman): >>I've worked on alot of machines where you cannot do ANY [structures in >>assignment, as parameters and as function return values]. >>Maybe that's not "right". Maybe one should boycott such compilers. Any >>way you look at it though it's still not portable. >This is a personal decision. Do you pander to every broken compiler? Or >do you concentrate on making the best code that will be accepted by any >correct compiler? >As for my opinion: If your compiler's broken, take it up with your vendor. Mild flame on. [The tone of Chip's comments irritate me.] If you have the option of only running on machines with compilers that you approve of and you can tell all relevant vendors that you want their compilers "fixed" and they will do it at your request, then your "personal decision" makes sense. Bully for you. Yes, I pander to broken compilers. I have to. I write software that runs on customers machines. It has to work on their machines. That is what portability in the real world is all about -- if you can take your code from machine A to machine B and compile and link it and have it work correctly then it's portable; if you can't then it is not. And the truth of the matter is that there is no penalty for writing portable code -- you can still write well structured, well documented code that is efficient. The things that make programs non portable are almost always frills and slop. Things like passing structures are frills. There are decision points in portability. When we decide not to run on system X because its compiler and operating system are too broken that is not a personal decision -- it is a simple economic decision that the market in system X is not worth pursuing. -- In the fields of Hell where the grass grows high Are the graves of dreams allowed to die. Richard Harter, SMDS Inc.
dawson@fpssun.fps.com (Bryan Dawson ext 1184) (10/20/88)
In article <2685@hound.UUCP>, rkl1@hound.UUCP (K.LAUX) writes: > In article <8810111934.AA21941@ucbarpa.Berkeley.EDU>, U23405@UICVM.Berkeley.EDU (Michael J. Steiner) writes: > > What I would like to know is (someone asked this before, I think): > > > > Is it considered portable to do the following things with > > structures or unions? > > -pass them (by value) to functions > > -have functions which return them > > -assign them (=) > > -test them (structures only) for equality with == > > > > Thanks in advance, > > > > Michael Steiner > > Email: U23405@UICVM.BITNET > > > *Why* would you want to do this anyway? It is far easier to use > pointers (and much more efficient). You should pass a *pointer* to the > struct/union, declare functions as *returning a pointer* to the struct/union, [ lots of good arguments for using pointers to structs deleted... ] Well, since you *did* ask, there are many very useful algorithms for sorting, searching, building, manipulating and accessing data structures which are *much* easier to use if the atomic 'data item' is passed into a functions *by value* and if functions can also generate *and then return* items of this type. For practical applications, this atomic 'data type' will usually be a structure with several fields. Some of these algorithms are recursive and require a 'new' instance of the structure on every call. This is done much more easily and naturally by passing the prior structure in *by value* modifying the new version and continuing. It is probably for good reasons like this that most good C compilers and the ANSI draft standard allow structures to be passed by value, returned from functions, and assigned as entities. Test for equality is prohibited by ANSI and seldom supported because it is troublesome to implement when the structures in question are padded internally and thus have undefined 'holes' within them which preclude a byte-for-byte test for equality. Please note that I do not disagree that pointers to structures are very natural and useful and can often be a more efficient method for manipulating structures with functions. I am merely pointing out that the use of structures as full-fledged entities sometimes has value which outwieghs the efficiency penalty for such use. It is sometimes important to note (especially in C) that efficiency is only ONE of MANY constraints on good program design. In situations where efficiency is not critical, I'll take readable, maintainable, simple and natural code which clearly follows the chosen algorithm any day... -- ============================================================================ = Bryan Dawson tektronix!fpssun!dawson ...The story you have just = = read is true, reality was subsequently changed to protect the innocent. = ============================================================================
chip@ateng.ateng.com (Chip Salzenberg) (10/25/88)
According to g-rh@XAIT.Xerox.COM (Richard Harter): > Yes, I pander to broken compilers. I have to. If I must work with a specific broken compiler, then I do the same: pay for play has its own rules. I was, of course, referring to situations where there *is* a choice, such as when writing free software, in which case I don't worry about it. > And the truth of the matter is that there is no penalty for >writing portable code [...] But there *is* a penalty in pandering to broken compilers. If, for example, a compiler breaks on: foo(s) short s; { short *sp = &s; int i = *sp; printf("%d\n", i); } Then you have to invest time and effort into avoiding a language construct -- taking the address of a function parameter -- that should have worked. (I know that some compilers do, in fact, break this contruct.) I'm sure all will agree that spent time and effort are just as much a "penalty" as execution time. -- Chip Salzenberg <chip@ateng.com> or <uunet!ateng!chip> A T Engineering Me? Speak for my company? Surely you jest! Beware of programmers carrying screwdrivers.
jas@ernie.Berkeley.EDU (Jim Shankland) (10/25/88)
In article <7356@ihlpl.ATT.COM> knudsen@ihlpl.ATT.COM (Knudsen) writes: >This is my main objection to structure and array assignment and >passing. Aside from being hideously wasteful of time and stack space, >they permit common typo errors (omission of &) to go undetected. Nonsense. Lint your code. ----- Jim Shankland jas@ernie.berkeley.edu "I've been walking in a river all my life, and now my feet are wet."
g-rh@XAIT.Xerox.COM (Richard Harter) (10/25/88)
In article <1988Oct24.172209.27031@ateng.ateng.com> chip@ateng.ateng.com (Chip Salzenberg) writes: >According to g-rh@XAIT.Xerox.COM (Richard Harter): >> Yes, I pander to broken compilers. I have to. >If I must work with a specific broken compiler, then I do the same: pay for >play has its own rules. I was, of course, referring to situations where >there *is* a choice, such as when writing free software, in which case I >don't worry about it. But how often do you really have a choice of compilers? If you have a small machine and you buy your compiler, yes, then you have a choice of compilers. If you are in an environment where you have a choice of machines, each with its own compiler, again you have a choice. More to the point, if your coding practices use constructs and techniques that break compilers, you are laying problems up for yourself and others in the future. Different people have different situations. I have high portability requirements; others do not. But I have been at this trade for a long time and I have noticed that life is a great deal simpler if you, as a matter of routine, assume that code may have to be ported. >> And the truth of the matter is that there is no penalty for >>writing portable code [...] >But there *is* a penalty in pandering to broken compilers. If, for example, >a compiler breaks on: > > foo(s) short s; > { > short *sp = &s; > int i = *sp; > > printf("%d\n", i); > } >Then you have to invest time and effort into avoiding a language construct >-- taking the address of a function parameter -- that should have worked. >(I know that some compilers do, in fact, break this contruct.) I'm sure all >will agree that spent time and effort are just as much a "penalty" as >execution time. This is a good example. It contains two coding techniques that I do not use and, indeed, would not think of using. The first is taking the address of a function parameter. The second is initialization to a dynamic quantity. Why do these things? The latter is just asking for trouble. The only reason for taking the address of a function parameter that I can think of is that you are calling a routine that requires a pointer rather than a value. I don't know whether they are "supposed" to work or not and I don't care; they are dubious constructs. More to the point, I do not agree and I am quite sure that many experience programmers do not agree with your assessment. There is a cost associated with learning a language -- the cost for learning to write it in a clean style is not much different than that of learning to write it any old way. Once you've learned what you can and cannot do, coding is simply a matter of writing within the language. Writing in language X is no harder or easier than writing in language Y, unless a language lacks a fundamental feature. Writing clean C is no harder than writing dirty C. But the price of writing dirty code is high -- debugging dirty code is a real pain, and it is a gratuitously assumed cost. Patient: "Doc, it hurts when I hit myself on the head with a hammer." Doctor: "Don't hit yourself on the head with a hammer." -- In the fields of Hell where the grass grows high Are the graves of dreams allowed to die. Richard Harter, SMDS Inc.
mouse@mcgill-vision.UUCP (der Mouse) (10/28/88)
From <8810111934.AA21941@ucbarpa.Berkeley.EDU>, by U23405@UICVM.Berkeley.EDU (Michael J. Steiner) >> Is it considered portable to do the following things with >> structures or unions? >> -pass them (by value) to functions Yes. >> -have functions which return them Yes. >> -assign them (=) Yes. >> -test them (structures only) for equality with == No. From <2685@hound.UUCP>, by rkl1@hound.UUCP (K.LAUX) > *Why* would you want to do this anyway? It is far easier to use > pointers (and much more efficient). It is often easier to use by-value, and in some cases it isn't much, if any, less efficient. If you use pointers all the time, you have to manage the storage for the pointers to point to. If you use structures by value, you can let the usual variable allocation mechanisms handle this for you. An example might be complex numbers. > If you are trying to get the compiler to automatically generate code > to copy the fields of the structure, *don't*. Why not? The compiler knows better than you do whether it can use clever machine-dependent tricks to get a fast copy.... > What you can do is declare a pair of *unsigned char* pointers and > cast the addresses of the source and destination structures to > 'unsigned char', then do a short loop to copy byte by byte based on > 'sizeof (struct)'. This will probably. But on a machine with an addressing unit larger than a char, you will pay a heavy efficiency penalty for this. On machines with a fast block move instruction, this almost certainly won't use it, and you take a performance hit again. That's what I meant above: the compiler knows all these tricks, or ought to, and can use the fastest one that applies. > As for testing equality of the contents of two unions/structures, go > through the effort of testing field by field - you can't go wrong > this way. More to the point, you can go wrong if you do a byte-compare, because of holes. It seems reasonable to me for equality testing of structures to generate code to compare all the members, but there are difficulties like what to do when with arrays of char; presumably this is why this isn't done. der Mouse old: mcgill-vision!mouse new: mouse@larry.mcrcim.mcgill.edu
jgp@moscom.UUCP (Jim Prescott) (11/03/88)
In article <2685@hound.UUCP> rkl1@hound.UUCP (K.LAUX) writes: > If you are trying to get the compiler to automatically generate code >to copy the fields of the structure, *don't*. What you can do is ... >a short loop to copy byte by byte based on 'sizeof (struct)'. Does ANSI guarantee that this would even work? I thought that attempting to read or write holes in structures was undefined (because they could actually be mapped out of your address space on some implementations). Thus anything that tried to look at all sizeof() bytes could fail. Is this correct? -- Jim Prescott moscom!jgp@cs.rochester.edu {rutgers,ames,harvard}!rochester!moscom!jgp