[comp.lang.c] still problems with ?:

maart@cs.vu.nl (Maarten Litmaath) (05/27/89)

chris@mimsy.UUCP (Chris Torek) writes:
\...
\But e1?e2:e3 *can* be turned into (e1&&e2 || !e1&&e3)

But what if e1 == *p++?
-- 
 "`Goto considered harmful' considered |Maarten Litmaath @ VU Amsterdam:
      harmful" considered harmful!     |maart@cs.vu.nl, mcvax!botter!maart

chris@mimsy.UUCP (Chris Torek) (05/31/89)

[me:]
>>But e1?e2:e3 *can* be turned into (e1&&e2 || !e1&&e3)

In article <2632@solo1.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) writes:
>But what if e1 == *p++?

In the original bogus article (<17722@mimsy.UUCP> [someday to be
mimsy.umd.edu]) I included various conditions, such as `no side
effects' and `used in a boolean context'.  I figured these were obvious
enough in the followup not to require another explication. . . .
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

dg@lakart.UUCP (David Goodenough) (06/07/89)

From article <2632@solo1.cs.vu.nl>, by maart@cs.vu.nl (Maarten Litmaath):
> chris@mimsy.UUCP (Chris Torek) writes:
> \...
> \But e1?e2:e3 *can* be turned into (e1&&e2 || !e1&&e3)
> 
> But what if e1 == *p++?

Simple:

((a = *p++) && e2 ) || (!a && e3)
-- 
	dg@lakart.UUCP - David Goodenough		+---+
						IHS	| +-+-+
	....... !harvard!xait!lakart!dg			+-+-+ |
AKA:	dg%lakart.uucp@xait.xerox.com		  	  +---+

spl@mcnc.org (Steve Lamont) (06/09/89)

In article <562@lakart.UUCP> dg@lakart.UUCP (David Goodenough) writes:
>From article <2632@solo1.cs.vu.nl>, by maart@cs.vu.nl (Maarten Litmaath):
>> chris@mimsy.UUCP (Chris Torek) writes:
>> \...
>> \But e1?e2:e3 *can* be turned into (e1&&e2 || !e1&&e3)
>> 
>> But what if e1 == *p++?
>
>Simple:
>
>((a = *p++) && e2 ) || (!a && e3)

Is right to left evaluation mandated in this case?  It seems to me that
I've been bitten by things like this before, either by non-standards
conforming compilers, ambiguous definition in the standard, my own
stupidity, or all of the above.  In any case, it seems that defensive
programming might dictate something like

	(a = *p++), ( ( a && e2 ) || (!a && e3) )

What say the gurus?  Or is this an RTFM?
-- 
							spl
Steve Lamont, sciViGuy			EMail:	spl@ncsc.org
North Carolina Supercomputing Center	Phone: (919) 248-1120
Box 12732/RTP, NC 27709

gwyn@smoke.BRL.MIL (Doug Gwyn) (06/09/89)

In article <4675@alvin.mcnc.org> spl@mcnc.org.UUCP (Steve Lamont) writes:
>>((a = *p++) && e2 ) || (!a && e3)
>Is right to left evaluation mandated in this case?  It seems to me that
>I've been bitten by things like this before, either by non-standards
>conforming compilers, ambiguous definition in the standard, my own
>stupidity, or all of the above.  In any case, it seems that defensive
>programming might dictate something like ...

There has never been any ambiguity about the correct sequence of
operations during evaluation of such an expression (except when
`p' is used in `e2' or `e3').  The outermost operator is ||; to
evaluate ex1||ex2 the compiler is obliged to generate code that
evaluates ex1 first, and ex2 only if necessary.  To evaluate ex1,
here ((a=*p++)&&e2), the stuff within the outermost parens must
be evaluated.  To evaluate that, the rules require that (a=*p++)
must be evaluated first, and e2 only if necessary. ... If ex2,
here (!a&&e3), is required to be evaluated, that is after ex1 has
been completely evaluated.  There is no ambiguity.

The point of C having assignment expressions, postincrement
operators, short-circuit evaluators, and so forth is precisely
to avoid having to use techniques such as your "defensive
programming" example.  Of course some vendor might offer what is
called a "C compiler" that gets basic expression evaluation wrong,
but if so, it would be virtually useless for the vast majority of
existing C source code.  I don't think you really need to guard
against totally broken compilers; if you start worrying about that,
there is no end to the things that "might" be done wrong..

spl@mcnc.org (Steve Lamont) (06/10/89)

In article <10387@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes:
>In article <4675@alvin.mcnc.org> spl@mcnc.org.UUCP (Steve Lamont) writes:
>>>((a = *p++) && e2 ) || (!a && e3)
>>Is right to left evaluation mandated in this case?  It seems to me that
>> [my paranoia deleted to save embarrassment]
>There has never been any ambiguity about the correct sequence of
>operations during evaluation of such an expression (except when
>`p' is used in `e2' or `e3').  The outermost operator is ||; to
>evaluate ex1||ex2 the compiler is obliged to generate code that

Right.  The FM (K&R, First Edition, p. 19) sez:

"Expressions connected by && or || are evaluated from left to right, and
it is guaranteed that evaluation will stop as soon as truth or falsehood
is known."

I should've looked before posting.  The thing I like about this group is
the sense of humility it brings to me!

>existing C source code.  I don't think you really need to guard
>against totally broken compilers; if you start worrying about that,
>there is no end to the things that "might" be done wrong..

Don't know if I exactly agree with that.  I've *had* to use some fairly
broken compilers... :-)
-- 
							spl
Steve Lamont, sciViGuy			EMail:	spl@ncsc.org
North Carolina Supercomputing Center	Phone: (919) 248-1120
Box 12732/RTP, NC 27709

dg@lakart.UUCP (David Goodenough) (06/12/89)

gwyn@smoke.BRL.MIL (Doug Gwyn) sez:
> In article <4675@alvin.mcnc.org> spl@mcnc.org.UUCP (Steve Lamont) writes:
>>>((a = *p++) && e2 ) || (!a && e3)
>>Is right to left evaluation mandated in this case?  It seems to me that
>>I've been bitten by things like this before, either by non-standards
>>conforming compilers, ambiguous definition in the standard, my own
>>stupidity, or all of the above.  In any case, it seems that defensive
>>programming might dictate something like ...
> 
> There has never been any ambiguity about the correct sequence of
> operations during evaluation of such an expression (except when
> `p' is used in `e2' or `e3').

Huh??? - if I use p in e2 or e3, my compiler had better use the value
_AFTER_ the *p++, otherwise I'm going to ask for my money back. In the
above code fragment if _ANYTHING_ is executed before the a = *p++ then
the compiler is broken. The same applies to:

	if ((a = *p++) ? e2 : e3)

The a = *p++ part has to be done first so that the compiler knows which
of e2 and e3 to do. Of course if your going to tell me that the standard
says that the a = *p and the p++ may happen at different times (i.e. the
p++ after e2), then I'm going to say the standard is broken.
-- 
	dg@lakart.UUCP - David Goodenough		+---+
						IHS	| +-+-+
	....... !harvard!xait!lakart!dg			+-+-+ |
AKA:	dg%lakart.uucp@xait.xerox.com		  	  +---+

karl@haddock.ima.isc.com (Karl Heuer) (06/15/89)

In article <568@lakart.UUCP> dg@lakart.UUCP (David Goodenough) writes:
>gwyn@smoke.BRL.MIL (Doug Gwyn) sez:
>>[The expression ((a = *p++) && e2 ) || (!a && e3) is well-defined]
>>(except when `p' is used in `e2' or `e3').
>
>Huh??? ... my compiler had better use the value _AFTER_ the *p++ ...

You're right; this is still unambiguous.  The pANS specifies that there is a
sequence point after the evaluation of the first operand of &&, ||, or ?:.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

dfp@cbnewsl.ATT.COM (david.f.prosser) (06/15/89)

In article <568@lakart.UUCP> dg@lakart.UUCP (David Goodenough) writes:
]gwyn@smoke.BRL.MIL (Doug Gwyn) sez:
]> In article <4675@alvin.mcnc.org> spl@mcnc.org.UUCP (Steve Lamont) writes:
]>>>((a = *p++) && e2 ) || (!a && e3)
]>>Is right to left evaluation mandated in this case?  It seems to me that
]>>I've been bitten by things like this before, either by non-standards
]>>conforming compilers, ambiguous definition in the standard, my own
]>>stupidity, or all of the above.  In any case, it seems that defensive
]>>programming might dictate something like ...
]> 
]> There has never been any ambiguity about the correct sequence of
]> operations during evaluation of such an expression (except when
]> `p' is used in `e2' or `e3').
]
]Huh??? - if I use p in e2 or e3, my compiler had better use the value
]_AFTER_ the *p++, otherwise I'm going to ask for my money back. In the
]above code fragment if _ANYTHING_ is executed before the a = *p++ then
]the compiler is broken. The same applies to:
]
]	if ((a = *p++) ? e2 : e3)
]
]The a = *p++ part has to be done first so that the compiler knows which
]of e2 and e3 to do. Of course if your going to tell me that the standard
]says that the a = *p and the p++ may happen at different times (i.e. the
]p++ after e2), then I'm going to say the standard is broken.
]-- 
]	dg@lakart.UUCP - David Goodenough		+---+
]						IHS	| +-+-+
]	....... !harvard!xait!lakart!dg			+-+-+ |
]AKA:	dg%lakart.uucp@xait.xerox.com		  	  +---+

David is correct:  There are sequence points at the appropriate
operators in these expressions.  Because all pending updates must
occur between the previous and the next sequence point, the update
to p in each of the following expressions must occur prior to the
evaluation of e2 or e3:

	(a = *p++) ? e2 : e3
		/* ^ sequence point */
	((a = *p++) && e2) || (!a && e3)
		/*  ^      ^      ^ sequence points */

But in
	((a = *p++) & e2) | (!a & e3)

there is no guarantee about the update of p with respect to the
evaluation of the rest of the expression.

Dave Prosser	...not an official X3J11 answer...

gwyn@smoke.BRL.MIL (Doug Gwyn) (06/17/89)

In article <568@lakart.UUCP> dg@lakart.UUCP (David Goodenough) writes:
>gwyn@smoke.BRL.MIL (Doug Gwyn) sez:
>> In article <4675@alvin.mcnc.org> spl@mcnc.org.UUCP (Steve Lamont) writes:
>>>>((a = *p++) && e2 ) || (!a && e3)
>> There has never been any ambiguity about the correct sequence of
>> operations during evaluation of such an expression (except when
>> `p' is used in `e2' or `e3').
>... Of course if your going to tell me that the standard
>says that the a = *p and the p++ may happen at different times (i.e. the
>p++ after e2), then I'm going to say the standard is broken.

No, the Standard specifies that there is a sequence point after the
evaluation of the first operand of && (also ||).

However, we were discussing pre-Standard C and what were universally
understood to be the rules back then versus what was considered not
clearly specified.  In K&R1, the sequencing of side effects was not
clearly specified, and consequently some C implementations deferred
the side effects in surprising ways, which is the point of my
parenthetical comment above.  X3J11 came up with the concept of
"sequence points" to permit accurate constraint specification in
this area.

andrew@alice.UUCP (Andrew Hume) (06/19/89)

i would second doug's comment.
a technique i have found useful (but not usable all the time) is for
routines to return a char *. on success this is 0, on error it is the actual
error message. simple to use, e.g.

	if(e = poot(args)){
		fprintf(stderr, "%s\n", e);
		exit(1);
	}