[comp.lang.c] use of if

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