expr?(void):(void) WHY I THINK IT'S *OK* ( or should be )
Gregory Smith
greg at utcsri.UUCP
Sun Aug 3 14:19:36 AEST 1986
In article <1983 at watmath.UUCP> rbutterworth at watmath.UUCP (Ray Butterworth) writes:
>I'm converted. I've seen the light. I'm studing the Bible much more
>closely. And look what I've found:
>
> comma-expression -> expression , expression
> The type and value of the result are the type and value
> of the right operand.
> DMR, Chapter 7, Verse 15.
>
>But, isn't that what it says about the "?:" expression too?
>Hallelujah! I've found a sin in our compiler. It actually
>allows those evil "void expressions" on the right of a comma.
>Why, this means we'll have to go back through the last few
>weeks of news, take all those articles talking about void
>functions and "?:" and repost them, this time changing the
>"?:" to ",", since all the arguments in them hold equally
>well.
>
>In the meantime, I urge everyone (well, those mentioned above anyway),
>to put the follwing fix into their compilers. I'm sure it will find
>many occurrences of this sin that may have crept into their code over
>the years.
BUT... BUT .... BUT...
you mean I can't
void a(),b(),c();
for( a(), b(); ... ; a(), c() ){
????????????????????
I can't even
i = ( a(), b(), 2 ); /* b() on RHS of 1st , */
???
This is getting worse! ( I strongly suspect Mr Butterworth agrees with me...)
There are two things going on in this debate:
(1) whether the Powers That Be condone e?void:void
(2) whether it makes sense and should be allowed.
I haven't the foggiest about (1) but I believe strongly that it *should* be
allowed. Herein is described in brief my belief system pertaining to this.
It is based on CONTEXTS, not an original idea by any means. There are
4 contexts of importance in C: The void context, the conditional context,
the value context, and the lvalue context.
- Any expression in a void context is evaluated for
side-effects only.
- Any expression in a conditional context is evaluated to
see if it is zero or non-zero. ( this is only significant
if the expression has a logical-valued operator at its top level ).
- The value of an expression in a value context is always used.
- There is another context, the Lvalue context, which will
only serve to cloud this particular issue, so I will
ignore it, and lump it under 'value'.
Let EV = expr in void context
EC = expr in cond context
EX = expr in value context.
Then
STMT ::= EV;
| while( EC ) STMT
| do STMT while( EC );
| for( EV; EC ; EV )STMT
| switch( EX )STMT
| if(EC) STMT
| if(EC) STMT else STMT
| return EX;
The above are all of the statement forms containing expressions (maybe
I missed a few ). The operators also create a particular context:
expr ::= EC && EC
EC || EC
! EC
EC ? EE : EE <<< looky
EV, EE <<< here
< any other unary op> EX
EX < any other binary op> EX
EX[EX], EX(), EX++,EX--, EX(EX,..) etc etc
( here's the point ) I haven't said what EE is. Any expression in an EE
context has the same effective context of the ',' or '?:' operator containing
it. I.e. the context is inherited. Thus:
if( x? p: q ) i ? a : b ;
Since the first ?: is in a EC context, p and q are in conditional contexts.
Likewise 'a' and 'b' are in void contexts. The expressions e1 and e2 below
are in a value context:
x = ( i<j? e1 : e2 );
Following this system, lint should complain about the second ?: below
but not the first:
int func(i){
void p(),q();
i ? p(): q(); /* value of p or q thrown away */
return (i==7)? p(): q(); /* value of p or q returned */
}
What really surprises me about all this... is that I always thought the
above was the Way It Is.
The e?void:void form is useful as the LHS of a comma op within an
expression ( esp with macros ). As has been pointed out so nicely by
rbutterworth, the VOID,VOID usage is very common, too.
if( foo) i=0, j=0; /* i=0 and j=0 both in void context */
j = ( i=0, x+y ); /* x + y in value context */
also, if you write (p(),q(),...) in any context, you expect to be allowed
to use a void q(), right? But q() is on the RHS of the first ,:
<groups as> ((p(),q()),...)
So the context of q() should be inherited through the inner ',' from
the LHS of the other ',' I.e., a void context.
This is much more than a language purity point - this kind of analysis
is necessary to generate decent testing code. If 'x<y' appears in
a conditional context, then the code merely sets the condition codes.
If it is in a value context, it must give 0 or 1. ( It is usually treated
in effect as 'x<y?1:0', i.e. the exp. is forced into a conditional
context). Also, consider
if( i? j: !k )
foobar();
which comes out as ( VAX 4.2 BSD , no -O )
tstl -4(fp) ; test i
jeql L9998 ; if i==0 goto L9998 { and test k }
tstl -8(fp) ; test j
jneq L9999 ; if j != 0 goto L9999 ( and call foobar())
jbr L16 ; if( i true but j false ) skip it
L9998:
tstl -12(fp) ; i is false. is k true?
jneq L16 ; skip if i false and k true.
L9999:
calls $0,_foobar
L16:
This is clearly optimal, and the compiler has obviously treated j and
!k in conditional contexts. Note the '9999' label numbers from the
code generator (L16 is from the parser for the 'if' ). If this system
is used, then the '!' operator will be 'free' in a conditional context
( on almost any machine ).
Lint obviously does *some* analysis of this, since it can say
"constant in conditional context". BTW, I have a program that gives
that error, but the expression is in an ARRAY DIMENSION for crissake.
char foo[ THING1 > THING2 ? THING1 : THING2 ];
Obviously it's going to be a constant. Any lint authors listening?
Turn that off when a constant expression is called for. While I'm
wishing for things, I wanna see 'assignment in conditional context'.
We all know why by now...
So what's the story? Isn't this The Way It Is? Doesn't the above make
a whole lotta sense? Why the *^&%#^&%&^@ would e?void:void _in_a_void_
_context_ be considered linty?
--
"You'll need more than a Tylenol if you don't tell me where my father is!"
- The Ice Pirates
----------------------------------------------------------------------
Greg Smith University of Toronto UUCP: ..utzoo!utcsri!greg
More information about the Comp.lang.c
mailing list