erik@mpx2.mpx.com (Erik Murrey) (07/17/89)
I'm curious how the gods feel about testing pointers in the following way (by example): char *cptr, *malloc(); /* ok, so maybe malloc is void * by now... */ x() { cptr= malloc(...); if (!cptr) fatal("cannot malloc"); ... } I know that sizeof(char *) != sizeof(int) on some machines, but the test of (!cptr) is for zero. It sure looks a lot better when you are testing complex pointers: struct xyzzy *sptr; char *malloc(); x() { sptr= (struct xyzzy *)malloc(...); if (sptr == (struct xyzzy *)NULL) /* (!sptr) would look better */ fatal("cannot malloc"); } Would (!sptr) break anywhere? Should it be discouraged? In fact, I much prefer (from a C style article posted a few years back): x() { if (sptr= (struct xyzzy *)malloc(...), !sptr) fatal("cannot malloc"); } Any problems with this? Thanks for your input. E-mail if you feel it is appropriate. ... Erik -- Erik Murrey /| // /~~~~/ | / MPX Data Systems, Inc. / | / / /____/ |/ erik@mpx.com / / / / /| Data Systems, Inc. {vu-vlsi, bpa, cbmvax}!mpx1!erik / / / / |====================
gwyn@smoke.BRL.MIL (Doug Gwyn) (07/17/89)
In article <10099@mpx2.mpx.com> erik@mpx2.mpx.com (Erik Murrey) writes: >Would (!sptr) break anywhere? Should it be discouraged? When sptr is a pointer variable, the following are equivalent: if(!sptr) if(sptr==0) if(sptr==NULL) /* assuming NULL is properly defined */ There is no need to cast the 0 (or NULL) to the type of sptr for this comparison. A common idiom is if ( (sptr = (type *)malloc( size )) == NULL )
ark@alice.UUCP (Andrew Koenig) (07/18/89)
In article <10099@mpx2.mpx.com>, erik@mpx2.mpx.com (Erik Murrey) writes: > char *cptr, *malloc(); /* ok, so maybe malloc is void * by now... */ > x() > { > cptr= malloc(...); > if (!cptr) > fatal("cannot malloc"); > ... > } No problem. The folowing expressions are all equivalent in this context: !cptr cptr==0 cptr==NULL cptr==(char *)0 cptr==(char *)NULL Which one you use is a matter of personal taste and style. -- --Andrew Koenig ark@europa.att.com
hascall@atanasoff.cs.iastate.edu (John Hascall) (07/18/89)
In article <10099@mpx2.mpx.com> erik@mpx2.mpx.com (Erik Murrey) writes: >I'm curious how the gods feel about testing pointers in the following >way (by example): Well, I'm probably not even a minor diety (yet :-) but here's an example of what I use: -------------------------- macro.h ------------------------------------------ #define ALLOC(type,count) \ ((type*)malloc(count*sizeof(type))) #define FATAL(string,val) \ return(fprintf(stderr, "[%4d] 0x0%x <- %s", __LINE__, val, string), val) #define ALLOCATE(ptr,type,count) \ if ((ptr=ALLOC(type,count)) == NULL) FATAL("alloc(ptr, type, count)", NULL) #define SYSCALL(function) \ if (((syscall_status = function)&1) == 0) FATAL("function", syscall_status) static int syscall_status; ---------------------------- foo.c ----------------------------------------- #include <descrip.h> #include <stdio.h> #include <stdlib.h> #include "macro.h" typedef struct foo { int bar; int baz; } FOO; main(argc,argv) int argc; char *argv[]; { $DESCRIPTOR( device, "ZZA0:"); unsigned short channel; FOO *cptr; int n_foo; n_foo = atoi(argv[1]); ALLOCATE(cptr, FOO, n_foo); SYSCALL(sys$assign(&device, &channel, 0, 0)); } ------------------------------------------------------------------- The SYSCALL macro really has nothing to do with memory allocation, it just happens to be in my "macro.h" file with the others, (it is a VMS-ism to boot), so I thought I'd through it out anyway. I wish I could come up with better names than "ALLOC" and "ALLOCATE" -- they are *too* similar. John Hascall / ISU Comp Center / Ames IA
paulc@microsoft.UUCP (Paul Canniff 2/1011) (07/19/89)
In article <10099@mpx2.mpx.com> erik@mpx2.mpx.com (Erik Murrey) writes: > >I'm curious how the gods feel about testing pointers in the following >way (by example): The gods are busy but left me an account to answer questions while they're away. This may explain the apparent contradiction between a perfect and benign deity and our imperfect world, but I am doing the best I can. >char *cptr, *malloc(); /* ok, so maybe malloc is void * by now... */ > >x() >{ > cptr= malloc(...); > if (!cptr) > fatal("cannot malloc"); > ... >} > >Would (!sptr) break anywhere? Should it be discouraged? It will break if NULL != 0. This is rare in my experience. In fact so rare that most programs would break in such an environment. Besides such obvious problems as the above code, there are places where an array set to zero is then assumed to be an array of NULL pointers, and numerous other implicit uses of the fact that NULL == 0 (usually). >In fact, I much prefer (from a C style article posted a few years back): > >x() >{ > if (sptr= (struct xyzzy *)malloc(...), !sptr) > fatal("cannot malloc"); >} This was from a *style* guide? Yeah I suppose it works, though I am too lazy to check if the comma operator has a guaranteed order of evaluation. I seldom use it. Anyway, why the spurious comma operator? Much simpler to write: if (! (sptr = (struct xyzzy *)malloc(...)) fatal(...); ------ Disclaimer goes here. This is my opinion and not Technical Support. It's all my fault.
campbell@redsox.bsw.com (Larry Campbell) (07/19/89)
We use macros called NIL and NEW: #define NIL(type) ((type) 0) #define NEW(type) ((type *) malloc(sizeof(type))) We also use typedefs to save typing and centralize type information, so the malloc example looks like this: typedef struct foo FOO; FOO *p; p = NEW(FOO); if (p == NIL(FOO *)) error(); I think this makes it pleasingly clear that you're testing for an invalid pointer, rather than the quantity zero. -- Larry Campbell The Boston Software Works, Inc. campbell@bsw.com 120 Fulton Street wjh12!redsox!campbell Boston, MA 02146
wen-king@cit-vax.Caltech.Edu (King Su) (07/19/89)
In article <93@microsoft.UUCP> paulc@microsoft.UUCP (Paul Canniff 2/1011) writes: <In article <10099@mpx2.mpx.com> erik@mpx2.mpx.com (Erik Murrey) writes: >>Would (!sptr) break anywhere? Should it be discouraged? < >It will break if NULL != 0. This is rare in my experience. In fact >This was from a *style* guide? Yeah I suppose it works, though I am <too lazy to check if the comma operator has a guaranteed order of ^^^^^^^^^^^^^^^^^ >evaluation. I seldom use it. Why do you bother to post anyway? The (!sptr) will never break and the comma operator do guarantee the order of evaluation. -- /*------------------------------------------------------------------------*\ | Wen-King Su wen-king@vlsi.caltech.edu Caltech Corp of Cosmic Engineers | \*------------------------------------------------------------------------*/
arrom@aplcen.apl.jhu.edu (Ken Arromdee) (07/19/89)
>It will break if NULL != 0. This is rare in my experience. ...
Not only rare, illegal.
--
"The fact is self evident from the text and requires no supporting argument."
--Tim Maroney
Kenneth Arromdee (UUCP: ....!jhunix!ins_akaa; BITNET: g49i0188@jhuvm;
INTERNET: arromdee@crabcake.cs.jhu.edu) (please, no mail to arrom@aplcen)
gwyn@smoke.BRL.MIL (Doug Gwyn) (07/19/89)
In article <93@microsoft.UUCP> paulc@microsoft.UUCP (Paul Canniff 2/1011) writes: >It will break if NULL != 0. malloc() is required to return a null pointer when it cannot allocate the storage. Having stashed that into a variable named "sptr", the test (!sptr) is required to correctly determine whether or not sptr is a null pointer, so the whole procedure is correct. What NULL may be defined as in some header is irrelevant here. Anyway, in standard headers that define NULL, NULL must be defined to be a valid generic null pointer (0 or (void*)0 for Standard C). There are some known bogus C implementations that define NULL as 0L or other warped flavors of 0, but I've never heard of one so far gone as to define NULL to be something totally unusable as a null pointer constant.
erik@mpx2.mpx.com (Erik Murrey) (07/19/89)
In article <93@microsoft.UUCP> >In article <10099@mpx2.mpx.com> erik@mpx2.mpx.com (Erik Murrey) writes: >> >>Would (!sptr) break anywhere? Should it be discouraged? > >It will break if NULL != 0. This is rare in my experience. In fact >so rare that most programs would break in such an environment. Besides >such obvious problems as the above code, there are places where an >array set to zero is then assumed to be an array of NULL pointers, >and numerous other implicit uses of the fact that NULL == 0 (usually). Yes, I know, but what happens when sizeof(int) != sizeof(char *)? My original question wasn't stated too clearly. Suppose a char * is 6 bytes, and an int is 4. Suppose the upper 2 bytes are used as some sort of descriptor. Now suppose malloc() returns a new memory block which just happens to be at the beginning of a new page, and our char * looks like: NN NN 00 00 00 00 (NNNN is our descriptor). Now, what happens with: if (cptr == 0) ? Does the compiler cast the cptr to an int, and loose the descriptor? (And tell is that it is null?) How about: if (!cptr) ? It would seem to me that the second example would probably work on such architectures, where the first might fail. On the other hand, I'm not a compiler writer. I but more nit picking: > >>In fact, I much prefer (from a C style article posted a few years back): >> >>x() >>{ >> if (sptr= (struct xyzzy *)malloc(...), !sptr) >> fatal("cannot malloc"); >>} > >This was from a *style* guide? Yes, and I wish I kept a machine copy to post. >Yeah I suppose it works, though I am >too lazy to check if the comma operator has a guaranteed order of >evaluation. I seldom use it. > >Anyway, why the spurious comma operator? Much simpler to write: > > if (! (sptr = (struct xyzzy *)malloc(...)) > fatal(...); > And most people seem to like this one best, although I dislike it because of the extra level of parentheses. Consider: struct xyzzy { int x; } *my_function(); { struct xyzzy *sptr; if ((sptr= my_function())->x == 0) printf("x is zero\n"); } vs. { struct xyzzy *sptr; if (sptr= my_function(), sptr->x == 0) printf("x is zero\n"); } I think the second is much clearer. This looks even better as the pointers get more complex, since the pointer operators go right on the ptr itself, and not on an expression. ... Erik -- Erik Murrey /| // /~~~~/ | / MPX Data Systems, Inc. / | / / /____/ |/ erik@mpx.com / / / / /| Data Systems, Inc. {vu-vlsi, bpa, cbmvax}!mpx1!erik / / / / |====================
chris@mimsy.UUCP (Chris Torek) (07/19/89)
In article <10100@mpx2.mpx.com> erik@mpx2.mpx.com (Erik Murrey) writes: >... what happens when sizeof(int) != sizeof(char *)? It makes no difference, if the compiler works. >Suppose a char * is 6 bytes, and an int is 4. Suppose the upper 2 bytes >are used as some sort of descriptor. Now suppose malloc() returns >a new memory block which just happens to be at the beginning of a new >page, and our char * looks like: > >NN NN 00 00 00 00 > >(NNNN is our descriptor). > >Now, what happens with: > >if (cptr == 0) ? Does the compiler cast the cptr to an int, and loose >the descriptor? (And tell is that it is null?) The comparison compiles into compare <register or memory holding cptr> against <canonical value for (char *)0> That is, if a nil pointer of type `pointer to char' happens to be represented by a descriptor value of 65535, it compares the descriptor field (NN NN) against 0xffff. If a nil pointer to char happens to be represented by six zero bytes, it compares all six bytes against zero. >How about: > >if (!cptr) ? `if (!cptr)' *means* `if (cptr == 0)', by the language definition; the compiler emits the same code sequence, or at least a code sequence that accomplishes the same thing, or else the compiler is broken. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
wjc@ho5cad.ATT.COM (Bill Carpenter) (07/20/89)
In article <10100@mpx2.mpx.com> erik@mpx2.mpx.com (Erik Murrey) writes: > struct xyzzy *sptr; > if (sptr= my_function(), sptr->x == 0) > printf("x is zero\n"); > > I think the second is much clearer. This looks even better as the > pointers get more complex, since the pointer operators go right > on the ptr itself, and not on an expression. Since there was no indication that this was intended as a joke ... I'll admit that this cloudy fragment looks clearer than the other one you cited, but what the heck is wrong with (besides not checking "sptr" being null): struct xyzzy *sptr; sptr= my_function(); if (sptr->x == 0) printf("x is zero\n"); Surely this "looks even better as the pointers get more complex" and the whole expression would otherwise dance off the left edge of the page? Why make the code hard to read when there isn't even a payoff? Is the point to show your pals in the Code Maintenance Garage that you know all about the comma operator? Or are you one of those poeple who gets paid proportional to the inverse number of source lines? :-) -- Bill Carpenter att!ho5cad!wjc or attmail!bill
john@frog.UUCP (John Woods) (07/20/89)
In article <93@microsoft.UUCP>, paulc@microsoft.UUCP (Paul Canniff 2/1011) writes: > >Would (!sptr) break anywhere? Should it be discouraged? > It will break if NULL != 0. It will break if-and-only-if your C compiler is broken. Read a C book, preferably the ANSI C spec. As far as discouragement goes, some feel that treating a pointer like a boolean is a mixing of abstractions that should be discouraged. Others (like myself) feel that treating it as success/failure makes the boolean interpretation quite natural. > > if (sptr= (struct xyzzy *)malloc(...), !sptr) > > fatal("cannot malloc"); > > This was from a *style* guide? Ew, ick, indeed! -- John Woods, Charles River Data Systems, Framingham MA, (508) 626-1101 ...!decvax!frog!john, john@frog.UUCP, ...!mit-eddie!jfw, jfw@eddie.mit.edu People...How you gonna FIGURE 'em? Don't bother, S.L.--Just stand back and enjoy the EVOLUTIONARY PROCESS...
jyegiguere@lion.waterloo.edu (Eric Giguere) (07/20/89)
The following quote from the draft ANSI Standard should be of interest: "An integral constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant." (3.2.2.3) and then later "NULL ... expands to an implementation-defined null pointer constant" (4.1.5) So even if your compiler uses its own non-zero internal representation for the null pointer, it must be able to catch expressions of the form if( ptr != 0 ) if( ptr != ( 10 * 10 - 101 + 1 ) ) if( ptr != (void *) (5-5) ) and your macro for NULL better expand to a zero-valued integer expression. Eric Giguere 268 Phillip St #CL-46 For the curious: it's French ("jee-gair") Waterloo, Ontario N2L 6G9 Bitnet : GIGUERE at WATCSG (519) 746-6565 Internet: giguere@aries5.UWaterloo.ca "Nothing but urges from HELL!!"
erik@mpx2.mpx.com (Erik Murrey) (07/21/89)
In article <WJC.89Jul19182602@ho5cad.ho5cad.ATT.COM> wjc@ho5cad.ATT.COM (Bill Carpenter) writes: >In article <10100@mpx2.mpx.com> erik@mpx2.mpx.com (Erik Murrey) writes: >> struct xyzzy *sptr; >> if (sptr= my_function(), sptr->x == 0) >> printf("x is zero\n"); >> >> I think the second is much clearer. This looks even better as the >> pointers get more complex, since the pointer operators go right >> on the ptr itself, and not on an expression. > >Since there was no indication that this was intended as a joke ... > >I'll admit that this cloudy fragment looks clearer than the other >one you cited, but what the heck is wrong with (besides not checking >"sptr" being null): > > struct xyzzy *sptr; > sptr= my_function(); > if (sptr->x == 0) > printf("x is zero\n"); Maybe its hard for you to read, but I'm used to it. Perhaps my example was bad. The above coding method is even more useful in while() and for() loops: while (cc= fgetc(fp), cc != '\n') { /* process more of line */ ... } or even: while (myptr= my_func(), myptr->x != myptr->y) { /* ... */ ... } I would kinda like to see that one in your style... ... Erik -- Erik Murrey /| // /~~~~/ | / MPX Data Systems, Inc. / | / / /____/ |/ erik@mpx.com / / / / /| Data Systems, Inc. {vu-vlsi, bpa, cbmvax}!mpx1!erik / / / / |====================
lacey@batcomputer.tn.cornell.edu (John Lacey) (07/21/89)
In article <10103@mpx2.mpx.com> erik@mpx2.mpx.com (Erik Murrey) writes: [Material everybody has seen n times deleted.] >Perhaps my example was bad. The above coding method is >even more useful in while() and for() loops: > >while (cc= fgetc(fp), cc != '\n') { > /* process more of line */ > ... >} > >or even: > >while (myptr= my_func(), myptr->x != myptr->y) { > /* ... */ > ... >} > >I would kinda like to see that one in your style... > I am kind of butting in [ :-) ], but how 'bout while ( (cc = fgetc(fp)) != '\n' ) { : } and while ( ( myptr = my_func() )->x != myptr->y ) { : } or even for ( myptr = my_func(); myptr->x != myptr->y; myptr = my_func() ) { : } though I use the last most commonly only when the two functions (primer and `incrementer') are different. Just a personal beef, maybe, but the comma operator slows me down when I'm reading code, and these example here don't. -- John Lacey | cornell!batcomputer!lacey lacey@tcgould.tn.cornell.edu | lacey@crnlthry.bitnet
ari@eleazar.dartmouth.edu (Ari Halberstadt) (07/21/89)
In article <10103@mpx2.mpx.com> erik@mpx2.mpx.com (Erik Murrey) writes: >Perhaps my example was bad. The above coding method is >even more useful in while() and for() loops: > >while (cc= fgetc(fp), cc != '\n') { > /* process more of line */ > ... >} That example is *certainly* not more useful. It is far better to use: while ((cc=fgetc(fp)) != '\n') It's standard (K&R used it all the time), and it's a little shorter. >or even: > >while (myptr= my_func(), myptr->x != myptr->y) { > /* ... */ > ... >} > >I would kinda like to see that one in your style... This example is much more appropriate, since I think it's the the only way todo this within the 'expr' part of the while loop. The other way to do it is: while (myptr = my_func() ) { if (myptr-> != myptr->y) break; /* ... */ } I think this latter method is used much more often. One place I've found the comma operator to be very useful is when an error must be handled and an error code returned from a function: if (error) return(perror("it failed"), FALSE); This saves the nuisance of using braces and two statements. while ((myptr-my_func())->x != -- Ari Halberstadt '91, "Long live succinct signatures" E-mail: ari@eleazar.dartmouth.edu Telephone: (603)640-5687 Mailing address: HB1128, Dartmouth College, Hanover NH 03755
ari@eleazar.dartmouth.edu (Ari Halberstadt) (07/21/89)
In article <8468@batcomputer.tn.cornell.edu> lacey@tcgould.tn.cornell.edu (John Lacey) writes: >In article <10103@mpx2.mpx.com> erik@mpx2.mpx.com (Erik Murrey) writes: >[Material everybody has seen n times deleted.] >I am kind of butting in [ :-) ], but how 'bout > while ( ( myptr = my_func() )->x != myptr->y ) > { > } THAT WILL NOT WORK! I quote here from the book "C Traps and Pit Falls" by Andrew Koenig (Addison-Wesley, 1989), pp. 47: Only the four C operators &&, ||, ?:, and , specify an order of evaluation. What this means for the above code is that the machine is free to evaluate "myptr->y" before "myptr" is assigned a value by my_func(). While it may work with a certain compiler on a certain machine, you may wake up tomorrow and discover some very wierd bugs! -- Ari Halberstadt '91, "Long live succinct signatures" E-mail: ari@eleazar.dartmouth.edu Telephone: (603)640-5687 Mailing address: HB1128, Dartmouth College, Hanover NH 03755
dwho@nmtsun.nmt.edu (David Olix) (07/22/89)
[Skipping all the "In article..." stuff] >[Material everybody has seen n times deleted.] >I am kind of butting in [ :-) ], but how 'bout > while ( ( myptr = my_func() )->x != myptr->y ) > { > } >THAT WILL NOT WORK! [...] Actually, "Mastering C" by Craig Bolon, SYBEX Inc., p. 273 says that parenthesis operators have the HIGHEST priority, therefore what's inside (myptr = my_func()) would get evaluated first. Also, it specifies that grouping for the '!=' operator is from left to right. Now, the author of this book may have been wrong.... Anyone seen an "official" statement from K&R? --David Olix (dwho@nmtsun.nmt.edu)
chris@mimsy.UUCP (Chris Torek) (07/22/89)
In article <2990@nmtsun.nmt.edu> dwho@nmtsun.nmt.edu (David Olix) writes: >> while ( ( myptr = my_func() )->x != myptr->y ) >>THAT WILL NOT WORK! [...] Or, more precisely, is not guaranteed. >Actually, "Mastering C" by Craig Bolon, SYBEX Inc., p. 273 says that >parenthesis operators have the HIGHEST priority, If by `priority' you mean (or Bolon means) `precedence', this is true, but: >therefore what's inside (myptr = my_func()) would get evaluated first. this conclusion is unwarranted. >Also, it specifies that grouping for the '!=' operator is from left to >right. This is again correct. Grouping and precedence are matters of parsing; that is, in the absence of parentheses, a != b != c is parsed the same way as (a != b) != c Parentheses, having extreme prej, er, precendence, can alter the grouping. But grouping is not related to order of evaluation. This should be obvious if you consider that while (a == b) has no grouping at all, but certainly does have *some* order of evaluation. Some languages (e.g., FORTRAN) make various constraints on evaluation order based on specific grouping constructs (e.g., parentheses), but traditionally, C has not done so. The pANS makes some limited constraints, but not enough to warrant the conclusion quoted above. In short, whether `myptr->y' is obtained before or after `(fncall)->x' is not defined in C, and different implementations do in fact have different evaluation order. Koenig's _C_Traps_and_Pitfalls_ is again correct. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
dpaulso@ark1.nswc.navy.mil (Dave Paulson) (07/22/89)
In article <14580@dartvax.Dartmouth.EDU> ari@eleazar.dartmouth.edu (Ari Halberstadt) writes: >[...] > >One place I've found the comma operator to be very useful is when an error >must be handled and an error code returned from a function: > if (error) > return(perror("it failed"), FALSE); >This saves the nuisance of using braces and two statements. I don't usually like to complain about other people's coding preferences, but this just struck a nerve. This is just plain ugly. When *I* see a comma operator, I tend to think of two things being done in parallel, so the impression I get when reading this segment is different from what is really going on. Besides, what's so doggone hard about adding a couple extra braces and semi-colons? Oh well, back to my cage.
ari@eleazar.dartmouth.edu (Ari Halberstadt) (07/22/89)
In article <2990@nmtsun.nmt.edu> dwho@nmtsun.nmt.edu (David Olix) writes:
#>[Skipping all the "In article..." stuff]
#>>[Material everybody has seen n times deleted.]
#>>I am kind of butting in [ :-) ], but how 'bout
#>> while ( ( myptr = my_func() )->x != myptr->y )
#>> {
#>> }
#>
#>>THAT WILL NOT WORK! [...]
#>
#>Actually, "Mastering C" by Craig Bolon, SYBEX Inc., p. 273 says that
#>parenthesis operators have the HIGHEST priority, therefore what's inside
#>(myptr = my_func()) would get evaluated first. Also, it specifies that
#>grouping for the '!=' operator is from left to right. Now, the author of
#>this book may have been wrong.... Anyone seen an "official" statement
#>from K&R?
True, parenthesis have the highest priority, but that is not relavent.
Syntactically, what you have is:
while (expr1 != expr2) { ... }
Since the two expressions are totally separate, the compiler is free
to do whatever it chooses. The expressions become a single expression when
(and only when) the compiler evaluates the != operator. The whole reason
for not defining order of evaluation was to allow machines to evaluate things
in the fastest way.
Grouping is not the same as order of evaluation...it's been a while since
I've gone over that, and I don't have a book in front of me right now.
The ANSI C standard has formalized all these things, but again, I don't
have a copy in front of me.
-- Ari Halberstadt '91, "Long live succinct signatures"
E-mail: ari@eleazar.dartmouth.edu Telephone: (603)640-5687
Mailing address: HB1128, Dartmouth College, Hanover NH 03755
ark@alice.UUCP (Andrew Koenig) (07/22/89)
In article <2990@nmtsun.nmt.edu>, dwho@nmtsun.nmt.edu (David Olix) writes: > [Skipping all the "In article..." stuff] > >[Material everybody has seen n times deleted.] > >I am kind of butting in [ :-) ], but how 'bout > > while ( ( myptr = my_func() )->x != myptr->y ) > > { > > } > > >THAT WILL NOT WORK! [...] > > Actually, "Mastering C" by Craig Bolon, SYBEX Inc., p. 273 says that > parenthesis operators have the HIGHEST priority, therefore what's inside > (myptr = my_func()) would get evaluated first. Also, it specifies that > grouping for the '!=' operator is from left to right. Now, the author of > this book may have been wrong.... Anyone seen an "official" statement > from K&R? I might as well put my two cents in. Precedence and order of evaluation are two different things. Precedence has to do with deciding what sub-expression is the operand of each operator. For example, the precedence rules of C say that a != b != c is equivalent to (a != b) != c and is not equivalent to a != (b != c) However, nowhere does C make any guarantee about the order in which a, b, and c will be fetched. It is completely legal for a C compiler to evaluate a != b != c by the following sequence of operations: copy b into register 1 copy c into register 2 copy a into register 3 compare registers 1 and 3 and put the result into register 0 compare registers 0 and 2 Similarly, in the expression ( myptr = my_func() )->x != myptr->y there is no doubt that the two things being compared are ( myptr = my_func() )->x and myptr->y However, the compiler is under no obligation to evaluate these two sub-expressions in any particular sequence. Only in the case of && || , and ?: operators does the compiler incur any such obligation. Thus, this expression could be rewritten: ( ( myptr = my_func() ), ( myptr->x != myptr->y ) ) to guarantee that the value of `myptr' used in the comparison would always be that returned by my_func(). Moreover, the precedence rules (not order of evaluation) allow the expression to be simplified slightly: ( myptr = my_func(), myptr->x != myptr->y ) with precisely the same effect. Finally, note that commas that separate function arguments are not comma operators. In this expression: my_other_func ( myptr = my_func(), myptr->x != myptr->y ) there is no guarantee of whether myptr is assigned before or after it is used to fetch the values of myptr->x and myptr->y. For such a guarantee, one would have to write myptr = my_func(), my_other_func ( myptr, myptr->x != myptr->y ) -- --Andrew Koenig ark@europa.att.com
gwyn@smoke.BRL.MIL (Doug Gwyn) (07/22/89)
In article <2990@nmtsun.nmt.edu> dwho@nmtsun.nmt.edu (David Olix) writes:
-> while ( ( myptr = my_func() )->x != myptr->y )
->THAT WILL NOT WORK! [...]
-Actually, "Mastering C" by Craig Bolon, SYBEX Inc., p. 273 says that
-parenthesis operators have the HIGHEST priority, therefore what's inside
-(myptr = my_func()) would get evaluated first. Also, it specifies that
-grouping for the '!=' operator is from left to right.
That's confusing precedence and associativity, which determine how to
parse the expression, with order of execution. Execution order is
mainly constrained by what are called "sequence points" in the pANS.
There are some sequence points within the expression, but not enough
to disambiguate the use of `myptr'.
les@chinet.chi.il.us (Leslie Mikesell) (07/23/89)
In article <10103@mpx2.mpx.com> erik@mpx2.mpx.com (Erik Murrey) writes: >while (myptr= my_func(), myptr->x != myptr->y) { > ... >} >I would kinda like to see that one in your style... I'd use: while (myptr = my_func() && myptr->x != myptr->y) { } which would detect a null pointer returned by my_func() as well as providing a guaranteed order of evaluation. Les Mikesell
george@rebel.UUCP (George M. Sipe) (07/23/89)
In article <37@ark1.nswc.navy.mil> dpaulso@ark1.nswc.navy.mil writes: >In article <14580@dartvax.Dartmouth.EDU> ari@eleazar.dartmouth.edu (Ari Halberstadt) writes: >>[...] >> return(perror("it failed"), FALSE); >>This saves the nuisance of using braces and two statements. > > I don't usually like to complain about other people's coding >preferences, but this just struck a nerve. > > This is just plain ugly. When *I* see a comma operator, I tend to think >of two things being done in parallel, so the impression I get when You see it wrong thing then. What you should see are two sequential operations. You are specifically assured of that. As for ugly, perhaps a better word would be unfamiliar. I personally haven't been (usually) coding that way, so it makes me think for a second when I see it. In some ways its more expressive. In the right frame of mind it may even be clearer. It seems to me that the comma operator is one of those elements of C which is not (at least) frequently seen in other languages, which fill a very useful role. It's sort of like comparing: some_very_long_variable_name = some_very_long_variable_name + 3; vs. some_very_long_variable_name += 3; You don't have to do it the second way. You could say the second way is ugly. You could argue that the first way is a "standard" method. Yet the second approach many would say is clearer. There is no confusion compared to the first approach where you would have to be careful that the same variable was referenced: some_very_long_variable_name = some_long_very_variable_name + 3; With the expressiveness of +=, you immediately see what is happening. I think the comma operator falls into that category as well, once you get confortable with it. -- George M. Sipe, Phone: (404) 447-4731 537 Lakeshore Drive, Berkeley Lake, GA 30136-3035 UUCP: ...!{decvax,linus,rutgers}!gatech!rebel!george
diamond@csl.sony.JUNET (Norman Diamond) (07/24/89)
Someone suggested: >>> while ( ( myptr = my_func() )->x != myptr->y ) In article <2990@nmtsun.nmt.edu> dwho@nmtsun.nmt.edu (David Olix) writes: >>THAT WILL NOT WORK! [...] Many people argued that it should work, because of the parentheses. (I almost did too, but continued reading first to see if anyone else did.) In article <18677@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes: >Or, more precisely, is not guaranteed. [...] >The pANS makes some limited constraints, but not enough to warrant the >conclusion [that it will work]. > >In short, whether `myptr->y' is obtained before or after `(fncall)->x' >is not defined in C, and different implementations do in fact have >different evaluation order. (Thanks to Chris Torek for closing my mouth before I put my foot in it.) But! What about the following famous idiom! int ch; /* everyone knows it cannot be char */ while ((ch = getchar()) != EOF) { ... } The old value of ch might be compared to EOF? The loop might be executed in incorrect cases (and might not be executed sometimes when it should be)? IS THIS REALLY TRUE ?????????????????? Are there really millions of broken C programs due to this idiom? -- -- Norman Diamond, Sony Computer Science Lab (diamond%csl.sony.jp@relay.cs.net) The above opinions are inherited by your machine's init process (pid 1), after being disowned and orphaned. However, if you see this at Waterloo or Anterior, then their administrators must have approved of these opinions.
jeffl@nc386.uucp (Jeff Leyser) (07/25/89)
In post <10562@smoke.BRL.MIL>, gwyn@brl.arpa (Doug Gwyn) says:
!In article <10100@mpx2.mpx.com> erik@mpx2.mpx.com (Erik Murrey) writes:
!>Now, what happens with:
!>if (cptr == 0) ? Does the compiler cast the cptr to an int, and loose
!>the descriptor? (And tell is that it is null?)
!
!We've already explained this, but here it is again: Just because you
!see "0" in the source code does not mean that it acts an integer constant.
OK, this may be meaningless, but out of curiosity is:
if (cptr == (int) 0)
illegal C, or simply compleat garbage?
--
Jeff Leyser ...!uunet!hal!ncoast!nc386!jeffl
chris@mimsy.UUCP (Chris Torek) (07/25/89)
In article <1989Jul24.194646.3012@nc386.uucp> jeffl@nc386.uucp (Jeff Leyser) writes: >OK, this may be meaningless, but out of curiosity is: > > if (cptr == (int) 0) > >illegal C, or simply compleat garbage? [where cptr was declared with `char *cptr;'] If it has a meaning, it means to compare cptr against a nil of type pointer-to-char. The question comes down to `is (int)0 an integral constant expression with value zero', because the way one writes the untyped nil pointer in C is to write an integral constant expression whose value is zero. Clearly (int)0 is an integral expression whose values is zero. Whether the cast takes away its `constant-ness' is less certain. Different compilers have had differing opinions in the past; what the current pANS says I am not sure (my copy is one or two revisions out of date, and is elsewhere at the moment anyway). The short answer is if (cptr == (int)0) is probably meaningful garbage. :-) -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
dandb@k.gp.cs.cmu.edu (Dean Rubine) (07/25/89)
A slightly better use of a comma in a while expression is: while(printf("? "), gets(line) != NULL) { ... whatever ... } I think it beats the alternatives: for(;;) { printf("? "); if(gets(line) == NULL) break; ... whatever ... } -- or -- for(printf("? "); gets(line) != NULL; printf("? ")) { ... whatever ... } I also occasionally use the comma to save braces: if((f = fopen(file, "r")) == NULL) fprintf(stderr, "Can't open %s\n", file), exit(2); -- ARPA: Dean.Rubine@CS.CMU.EDU UUCP: ...!seismo!k.gp.cs.cmu.edu!dandb PHONE: 412-268-2613 [ Free if you call from work] US MAIL: Computer Science Dept / Carnegie Mellon U / Pittsburgh PA 15213 DISCLAIMER: My employer wishes I would stop posting and do some work.
reinier@cwi.nl (R v/d Born) (07/25/89)
In article <10100@mpx2.mpx.com> erik@mpx2.mpx.com (Erik Murrey) writes: > >In article <93@microsoft.UUCP> >>In article <10099@mpx2.mpx.com> erik@mpx2.mpx.com (Erik Murrey) writes: >>> >>>Would (!sptr) break anywhere? Should it be discouraged? >> >>It will break if NULL != 0. This is rare in my experience. In fact >>so rare that most programs would break in such an environment. Besides >>.... >Yes, I know, but what happens when sizeof(int) != sizeof(char *)? My >original question wasn't stated too clearly. > >Suppose a char * is 6 bytes, and an int is 4. Suppose the upper 2 bytes >are used as some sort of descriptor. Now suppose malloc() returns >..... > >if (cptr == 0) ? Does the compiler cast the cptr to an int, and loose >the descriptor? (And tell is that it is null?) >..... >Erik Murrey Let us take a look at the pANS. 1) section 3.3.3.3: (about the ! operator) The result of the logical negation operator ! is 0 if the value of its operand compares unequal to 0, 1 if the value of its operand compares equal to 0. The result type is int. 2) section 3.2.2.3: (about NULL and 0) An integral constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. If a null pointer constant is assigned to or compared for equality to a pointer, the constant is converted to a pointer of that type. Such a pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function. Two null pointers, converted through a possible different sequence of casts to pointer types, shall compare equal. (sorry for the loss of italics and special fonts :-) So we may conclude that the expression: (! cptr) is evaluated as (cptr == (cast to cptr type) 0) and therefor never fail to detect NULL. Likewise the value of the test expression in an if, while, etc. is compared with 0 (see sections on statements). So if (ptr) is equivalent with if (ptr != 0) which is equivalent with if (ptr != (ptr type) 0) Note that pANS doesn't prescribe the use of a pointer consisting of all 0s to represent NULL, nor does it say anything about the sizes of a pointers (which may differ for different objects they point to). It rather forces the compiler to reserve a special representation and convert 0 to that representation before performing the comparison. So things like f( ptr ) int *ptr; { if (ptr) .... } ... f( 0 ); won't work when, for instance, using the compiler I am working on. But what the heck, that should teach people writing such code (:-) Reinier van den Born Parallel Computing s-nail: Postbus 16775, 1001 RG Amsterdam, The Netherlands e-mail: reinier@cwi.nl
walter@hpclwjm.HP.COM (Walter Murray) (07/26/89)
Jeff Leyser writes: > OK, this may be meaningless, but out of curiosity is: > if (cptr == (int) 0) > illegal C, or simply compleat garbage? It's perfectly legal, if a little misleading. As a further examle of the latitude you have in writing a null pointer constant, the following would also be legal. if (cptr == (signed short)0.3+sizeof(char)-'\1' +sizeof((long int*)myfunc()+3,000)-sizeof'M'); I think any ANSI-conforming compiler will accept this statement. Walter Murray Not speaking for Hewlett-Packard or X3J11
raph@tigger.planet.bt.co.uk (Raphael Mankin) (07/28/89)
ari@eleazar.dartmouth.edu (Ari Halberstadt) writes: >In article <2990@nmtsun.nmt.edu> dwho@nmtsun.nmt.edu (David Olix) writes: >#>[Skipping all the "In article..." stuff] >#>>[Material everybody has seen n times deleted.] >True, parenthesis have the highest priority, but that is not relavent. >Syntactically, what you have is: > while (expr1 != expr2) { ... } >Since the two expressions are totally separate, the compiler is free >to do whatever it chooses. The expressions become a single expression when >(and only when) the compiler evaluates the != operator. The whole reason >for not defining order of evaluation was to allow machines to evaluate things >in the fastest way. >Grouping is not the same as order of evaluation...it's been a while since >I've gone over that, and I don't have a book in front of me right now. >The ANSI C standard has formalized all these things, but again, I don't >have a copy in front of me. The order of evaluation of operands and the order of application of operators have little to do with each other. The compiler could evaluate _all_ the operands before applying _any_ operators (except && ||). This applies also to the order of evaluation of subscripts and function arguments. If there are side effects you are in dangerous waters - so don't do it. A typical, and particularly blatant, case is a[i] = b[i++]; or a[i++] = b[i]; Some compilers will diagnose this. although the compiler has to compute the RHS before it uses the LHS, there is nothing to stop it evaluating the LHS so as to obtain the destination address before evaluating the RHS.
ark@alice.UUCP (Andrew Koenig) (08/02/89)
In article <10592@riks.csl.sony.JUNET>, diamond@csl.sony.JUNET (Norman Diamond) writes: > But! What about the following famous idiom! > int ch; /* everyone knows it cannot be char */ > while ((ch = getchar()) != EOF) { ... } > The old value of ch might be compared to EOF? The loop might be > executed in incorrect cases (and might not be executed sometimes when > it should be)? > IS THIS REALLY TRUE ?????????????????? > Are there really millions of broken C programs due to this idiom? No, this works fine. The reason it works is that both operands of an operator must be completely evaluated before the operator itself is [unless the operator is && or || or ?:]. Thus, before the comparison is done, the two subexpressions ch = getchar() and EOF must be evaluated. There is no guarantee of which one is evaluated first, but you can't compare two values until you know what they are. -- --Andrew Koenig ark@europa.att.com
gwyn@smoke.BRL.MIL (Doug Gwyn) (08/02/89)
In article <10592@riks.csl.sony.JUNET> diamond@riks. (Norman Diamond) writes: >But! What about the following famous idiom! > while ((ch = getchar()) != EOF) { ... } >The old value of ch might be compared to EOF? No -- however, EOF may be evaluated before ch is set to what getchar() returns (before the comparison of the new value of ch against EOF).
glen@astroatc.UUCP (Glen Ecklund) (08/02/89)
In article <10592@riks.csl.sony.JUNET> diamond@riks. (Norman Diamond) writes: ->Someone suggested: ->>>> while ( ( myptr = my_func() )->x != myptr->y ) -> ->In article <18677@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes: ->>In short, whether `myptr->y' is obtained before or after `(fncall)->x' ->>is not defined in C, and different implementations do in fact have ->>different evaluation order. -> ->But! What about the following famous idiom! -> -> int ch; /* everyone knows it cannot be char */ -> while ((ch = getchar()) != EOF) { ... } -> ->The old value of ch might be compared to EOF? Nope. Note that in the first example, the problem is not that the left use of myptr might get the wrong value, it is guaranteed to get the value returned by my_func(). The problem is that the right use of myptr could get either. The value of the expression (ch = getchar()) will similarly always be the value returned by getchar(). No problem. Glen
mouse@mcgill-vision.UUCP (der Mouse) (08/09/89)
In article <660046@hpclwjm.HP.COM>, walter@hpclwjm.HP.COM (Walter Murray) writes: > As a further exam[p]le of the latitude you have in writing a null > pointer constant, the following would also be legal. > if (cptr == (signed short)0.3+sizeof(char)-'\1' > +sizeof((long int*)myfunc()+3,000)-sizeof'M'); > I think any ANSI-conforming compiler will accept this statement. Leaving aside the point (on which even Chris Torek is unsure) of whether or not a cast produces a non-"constant" expression, this is valid only if sizeof(long int *) equals sizeof(int), which isn't true everywhere. Your expression also requires that myfunc() be declared (possibly implicitly) as returning something that can be cast into (long int *); this might not be true (eg, it may return a struct). Question: If it does happen that sizeof(long int *) == sizeof(int), is it correct to write "if (cptr == sizeof(long int *)-sizeof(int))"? In other words, must we compare against an integer constant expression which is guaranteed to be zero or may we get away with using one which just happens to be zero for the compilation environment in use? I'd guess it's the latter, but am curious. If I'm right, is it then possible to use this as a means of drawing a guaranteed compile-time warning if sizeof(long int *) is *not* equal to sizeof(int), or are compilers not required to warn about pointer/int mismatches like that? (Yes, I know the warning probably will not be very descriptive of the *real* problem. :-) der Mouse old: mcgill-vision!mouse new: mouse@larry.mcrcim.mcgill.edu
dfp@cbnewsl.ATT.COM (david.f.prosser) (08/10/89)
In article <1603@mcgill-vision.UUCP> mouse@mcgill-vision.UUCP (der Mouse) writes: >In article <660046@hpclwjm.HP.COM>, walter@hpclwjm.HP.COM (Walter Murray) writes: >> As a further exam[p]le of the latitude you have in writing a null >> pointer constant, the following would also be legal. > >> if (cptr == (signed short)0.3+sizeof(char)-'\1' >> +sizeof((long int*)myfunc()+3,000)-sizeof'M'); > >> I think any ANSI-conforming compiler will accept this statement. > >Leaving aside the point (on which even Chris Torek is unsure) of >whether or not a cast produces a non-"constant" expression, this is >valid only if sizeof(long int *) equals sizeof(int), which isn't true >everywhere. Not as far as I can see. The relevant part of the expression is sizeof((long int*)myfunc()+3,000)-sizeof'M' and as the first sizeof expression is actually a (hidden) comma expression, it is equivalent to sizeof(000)-sizeof'M' Since 000 is an (octal) int constant, it must be the same size as 'M'. > >Your expression also requires that myfunc() be declared (possibly >implicitly) as returning something that can be cast into (long int *); >this might not be true (eg, it may return a struct). Assuming no other information, then myfunc() is implicitly declared to return int. Any integral type can be converted to any pointer type with a cast. The result of the conversion is implementation-defined, but the conversion is valid. > >Question: If it does happen that sizeof(long int *) == sizeof(int), is >it correct to write "if (cptr == sizeof(long int *)-sizeof(int))"? In >other words, must we compare against an integer constant expression >which is guaranteed to be zero or may we get away with using one which >just happens to be zero for the compilation environment in use? This is an example of a "conforming" program, instead of the above which, as far as I can tell, is "strictly conforming". (A strictly conforming program works on all conforming implementations; a conforming program is acceptable to at least one conforming implementation.) > >I'd guess it's the latter, but am curious. > >If I'm right, is it then possible to use this as a means of drawing a >guaranteed compile-time warning if sizeof(long int *) is *not* equal to >sizeof(int), or are compilers not required to warn about pointer/int >mismatches like that? (Yes, I know the warning probably will not be >very descriptive of the *real* problem. :-) You are correct: a diagnostic is required for an equality test of a pointer with a nonzero integral expression. Just how useful this is is not at all clear. Dave Prosser ...not an official X3J11 answer...
gwyn@smoke.BRL.MIL (Doug Gwyn) (08/15/89)
In article <10100@mpx2.mpx.com> erik@mpx2.mpx.com (Erik Murrey) writes: >Now, what happens with: >if (cptr == 0) ? Does the compiler cast the cptr to an int, and loose >the descriptor? (And tell is that it is null?) We've already explained this, but here it is again: Just because you see "0" in the source code does not mean that it acts an integer constant. In this context it is taken as (technically, is converted to) a null pointer of the appropriate type. A null pointer need not have an all-0 bit representation, but "0" is still the way you write it in C source code. In effect, the apparent integer constant "0" is converted to a pointer in this context; the pointer is not converted to int. >How about: >if (!cptr) ? Completely equivalent to "if(cptr==0)".
mouse@mcgill-vision.UUCP (der Mouse) (08/18/89)
In article <1429@cbnewsl.ATT.COM>, dfp@cbnewsl.ATT.COM (david.f.prosser) writes: > In article <1603@mcgill-vision.UUCP> mouse@mcgill-vision.UUCP (der Mouse) writes: >> In article <660046@hpclwjm.HP.COM>, walter@hpclwjm.HP.COM (Walter Murray) writes: >>> As a further exam[p]le of the latitude you have in writing a null >>> pointer constant, the following would also be legal. >>> if (cptr == (signed short)0.3+sizeof(char)-'\1' >>> +sizeof((long int*)myfunc()+3,000)-sizeof'M'); >> [T]his is valid only if sizeof(long int *) equals sizeof(int), which >> isn't true everywhere. > Not as far as I can see. The relevant part of the expression is > sizeof((long int*)myfunc()+3,000)-sizeof'M' > and as the first sizeof expression is actually a (hidden) comma > expression, Argh. You are, of course, correct. (Strange how easy it is to misread 3,000 as 3000.) >> Your expression also requires that myfunc() be declared (possibly >> implicitly) as returning something that can be cast into (long int *); > Assuming no other information, then myfunc() is implicitly declared > to return int. That's what my "possibly implicitly" was intended to anticipate. >> [I]s it then possible to use this as a means of drawing a guaranteed >> compile-time warning if [sizeof(long int *) != sizeof(int)] [...]? > [Yes.] Just how useful this is is not at all clear. Well, no, I can't exactly claim to have a use in mind for it. But it seems like something that it might be nice to be able to do. (It's easy to check at run-time, of course, but not all compilers are bright enough to eliminate the dead code, and occasionally you can't afford the extra clutter.) der Mouse old: mcgill-vision!mouse new: mouse@larry.mcrcim.mcgill.edu