[comp.lang.c] Style question re common C expression.

flaps@utcsri.UUCP (06/15/87)

Frequently I write expressions of the form "x ? x : y".  For example,
in unix where "getenv" returns an environment variable, I might have
something like:
	char *t;
	execl((t = getenv("EDITOR")) ? t : "/bin/ed",file,(char *)NULL);
to run the user-specified editor, with a default of /bin/ed.

My complaint about this syntax is mostly about having to use the
temporary variable.  I know assembler-level optimizers will elide it,
but the point is that there is actually no operations happening
conceptually between the '?' and the ':' and I don't think I should
have to specify them.

I think that "getenv("EDITOR") ? : "/bin/ed"" should do what I mean
here.  Unfortunately this is not supported; also, the expression
"getenv("EDITOR") || "/bin/ed"" doesn't work because the value of the
getenv is converted to 1 or 0.

Also, in my current large project, for example, I have some functions
which can accept pointers or NULLs for return values: for example,

	void f(ip)
	int *ip;
	{
	    int trash;
	    ...
	    *(ip ? ip : &trash) = something;

The same syntax applies here.  (This can't be converted to an if
statement because actually the pointer is passed to another function
which dereferences it.)

So the main question is, is there some nice way I missed to specify
this?

And the secondary question is, if not then is there a standard macro
name and syntax I should use, like the standard "#define
STREQ(s,t)(strcmp(s,t) == 0)"?

-- 

      //  Alan J Rosenthal
     //
 \\ //        flaps@csri.toronto.edu, {seismo!utai or utzoo}!utcsri!flaps,
  \//              flaps@toronto on csnet, flaps at utorgpu on bitnet.


"To be whole is to be part; true voyage is return."

henry@utzoo.UUCP (Henry Spencer) (06/18/87)

> ... like the standard "#define STREQ(s,t)(strcmp(s,t) == 0)"?

This is slightly off the topic, but note two things:

First, that should be "(strcmp((s),(t)) == 0)" for safety's sake, although
in this case trouble is unlikely.

Second, if you don't indulge in the perversion of routinely using side
effects within expressions, then a still better form is:

#define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)

This makes a considerable speed difference in programs that use strings
a lot, since string comparisons usually fail on the very first character.
-- 
"There is only one spacefaring        Henry Spencer @ U of Toronto Zoology
nation on Earth today, comrade."   {allegra,ihnp4,decvax,pyramid}!utzoo!henry

karl@haddock.UUCP (Karl Heuer) (06/19/87)

In article <4934@utcsri.UUCP> flaps@utcsri.UUCP (Alan J Rosenthal) writes:
>Frequently I write expressions of the form "x ? x : y".  For example,
>in unix where "getenv" returns an environment variable, I might have
>something like: ... (t = getenv("EDITOR")) ? t : "/bin/ed" ...
>My complaint about this syntax is mostly about having to use the
>temporary variable.

I partially agree; one measure of the power of an operator (or language) is
its ability to save you a temporary variable.

I once proposed extending the "||" operator to do what you want -- this would
break only those rare programs that pass non-booleans to "||" *and* use the
result in a non-boolean context -- but decided it was a bad idea because

(a) it blurs the distinction between boolean and integer, which is already
fuzzy in C; and

(b) (really a consequence of (a), I guess) it's not quite as powerful as such
a construct could be, because the only comparison allowed is equality with 0.
(Consider the similar example "(c=getchar()) != EOF ? c : defchar".)

So, with tongue in cheek, I proposed the new syntax:
	getenv() unless ==0 inwhichcase "/bin/ed"
(which immediately inspired my colleague to propose the "ifontheotherhand ...
wemaysafelyassume" construct).

Actually, I think what you really want is a pronoun.  I first encountered this
in PDL, in the construct
   if token_scanner_backed_up_flag is set
      unset it
      ...
   endif
; given this, your expression is just (getenv() ? it : "/bin/ed") and mine is
(getchar() == EOF ? defchar : it).  Of course, the problem now becomes one of
defining the antecedent of the pronoun in a consistent way.

>So the main question is, is there some nice way I missed to specify this?

No, you need an explicit temporary (or a function call, in which the formal
argument is the temporary).

>And the secondary question is, if not then is there a standard macro
>name and syntax I should use, like the standard [STREQ macro]?

How will putting it into a macro solve anything?  You still need the temp, and
for a general macro you don't even have a consistent type for it.  (Integer or
pointer?  Pointer to what?)  I recommend you leave it as inline code.

(Or else make a smarter function -- I don't bother for string getenv, but for
reading numbers from the environment I've found
   int env(char *name, int defval) {
      char *ep;
      return ((ep = getenv(name)) == NULL || *ep == '\0' ? defval : atoi(ep));
   }
useful at times.)

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

chips@usfvax2.UUCP (Chip Salzenberg) (06/23/87)

In article <8164@utzoo.UUCP>, henry@utzoo.UUCP writes:
> > ... like the standard "#define STREQ(s,t)(strcmp(s,t) == 0)"?
> 
> [Note:]
> First, that should be "(strcmp((s),(t)) == 0)" for safety's sake, although
> in this case trouble is unlikely.

I can't think of any situation which could break the macro given by Henry.
In a spirit of curiosity -- can you come up with an invocation of the above-
quoted "STREQ(s,t) (strcmp(s,t)==0)" macro that would not behave as expected?
-- 
Chip Salzenberg		    Address: "{gatech,cbatt,akgua}!usfvax2!ateng!chip"
AT Engineering, Tampa, FL   Redress: "chips@usfvax2.UUCP"
"Use the Source, Luke!"	    My opinions do not necessarily agree with anything.

karl@haddock.UUCP (Karl Heuer) (06/23/87)

In article <8164@utzoo.UUCP> henry@utzoo.UUCP (Henry Spencer) writes:
>> ... like the standard "#define STREQ(s,t)(strcmp(s,t) == 0)"?
>
>This is slightly off the topic, but note two things:
>
>First, that should be "(strcmp((s),(t)) == 0)" for safety's sake, although
>in this case trouble is unlikely.

Unlikely?  I think in this case it's impossible.  But you're right in that
it's a good habit to get into, and it certainly doesn't hurt.

>Second, if you don't indulge in the perversion of routinely using side
>effects within expressions, then a still better form is:
>
>#define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)

Some people would phrase that the other way around: "If you don't indulge in
the perversion of writing macros that evaluate their arguments more than once,
then you can write f(p++), using them just like functions."

>This makes a considerable speed difference in programs that use strings
>a lot, since string comparisons usually fail on the very first character.

Of course, a really good compiler will make "strcmp" a builtin, giving you the
same speed improvement without sacrificing any of the calling contexts.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
(Btw, the name "STREQ" isn't all that standard.  I spell it "streq", myself.)

mouse@mcgill-vision.UUCP (der Mouse) (06/27/87)

In article <8164@utzoo.UUCP>, henry@utzoo.UUCP (Henry Spencer) writes:
>> ... like the standard "#define STREQ(s,t)(strcmp(s,t) == 0)"?

> [Second,] if you don't indulge in the perversion of routinely using
> side effects within expressions, then a still better form is:

> #define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)

Perversion?  You mean, as in

docommand(cmd)
register char *cmd;
{
 register char **cmdptr;

 cmdptr = commands;                              /* vvvvvvvvv */
 while ((cmdptr < commands+NCOMMANDS) && !STREQ(cmd,*cmdptr++)) ;
 (*cmdfxns[cmdptr-commands])(cmd); /* assumes extra entry for bad cmd */
}

					der Mouse

				(mouse@mcgill-vision.uucp)

henry@utzoo.UUCP (Henry Spencer) (07/06/87)

> > [Second,] if you don't indulge in the perversion of routinely using
> > side effects within expressions...
> 
> Perversion?  You mean, as in...

After looking at the sample code shown, I had to go and lie down for a
while :-), so I fear I can't comment on it except to say:  perversion!
-- 
Mars must wait -- we have un-         Henry Spencer @ U of Toronto Zoology
finished business on the Moon.     {allegra,ihnp4,decvax,pyramid}!utzoo!henry