replacement of 'if' ?

M

Mark

Hello

I recently encountered this slightly obfiscating code:

void foo(int a)
{
a > 0 && puts("+");
}

seems this is to replace 'if-else' chain as in:

if (a > 0)
printf();
....

But I can't precisely understand the underlying mechanics of '&&' operator
above: 'a > 0' evaluates 1 or 0 depending on the value of 'a', but how does
&& apply to the second operand, which is function ?
 
C

Chris Dollin

Mark said:
Hello

I recently encountered this slightly obfiscating code:

void foo(int a)
{
a > 0 && puts("+");
}

seems this is to replace 'if-else' chain as in:

if (a > 0)
printf();
...

But I can't precisely understand the underlying mechanics of '&&' operator
above: 'a > 0' evaluates 1 or 0 depending on the value of 'a', but how does
&& apply to the second operand, which is function ?

It doesn't matter what the right operand of `&&` is; the evaluation
rule is: evaluate the left operand; yeild 0 if that yeilded 0; otherwise
evaluate the right operand and yeild whatever that yeilds.

(The second operand of `&&` above isn't a function, it's a function
/call/.)

--
'"Why is it," I asked Will, after the seventh or eigth time, /Deep Secret/
"that they see a thing and don't know what it is, and I tell
them that it's an unidentified flying object, and they go away
perfectly satisfied?"

Hewlett-Packard Limited Cain Road, Bracknell, registered no:
registered office: Berks RG12 1HN 690597 England
 
M

Mark

Chris Dollin said:
It doesn't matter what the right operand of `&&` is; the evaluation
rule is: evaluate the left operand; yeild 0 if that yeilded 0; otherwise
evaluate the right operand and yeild whatever that yeilds.

(The second operand of `&&` above isn't a function, it's a function
/call/.)
Thank you, you've cleared my doubts.
 
K

Keith Thompson

Chris Dollin said:
It doesn't matter what the right operand of `&&` is; the evaluation
rule is: evaluate the left operand; yeild 0 if that yeilded 0; otherwise
evaluate the right operand and yeild whatever that yeilds.

Close, but not quite.

Both operands of "&&" have to be scalar. puts() returns an int, so it
can be used here; a call to a function returning void would be
invalid.

The "&&" operator yields 1 if both its operands are non-zero, 0
otherwise.

If the left operand is 0, the right operand is not evaluated, which is
what makes it act like an if statement. But using an if statement
would have been clearer.

(This kind of thing is a fairly common idiom in shell scripts.)

[...]
 
M

Mark

Keith Thompson said:
Both operands of "&&" have to be scalar. puts() returns an int, so it
can be used here; a call to a function returning void would be
invalid.

The "&&" operator yields 1 if both its operands are non-zero, 0
otherwise.

So I also may write:

fprintf(...) || exit(EXIT_FAILURE);

The '||' operator will yield 1 if at least one operand is non-zero, in other
words if 'fprintf' fails, the 'exit' call is invoked and this would be equal
to:

if (fprintf(..) == 0)
exit();
 
C

Chris Dollin

Keith said:
Close, but not quite.

Both operands of "&&" have to be scalar.

Yes, but that wasn't the "didn't matter" I meant (since, if an
operand was not scalar, then there's a constraint violation, and
All Bets Are Off as to any run-time behaviour); I meant that it
didn't matter that the right operand was a function [call] rather
than a variable or a sum or whatever. I should have accounted for
that.

I was ... distracted. Yes. That's it. Distracted.
 
K

Keith Thompson

Mark said:
So I also may write:

fprintf(...) || exit(EXIT_FAILURE);

Well, you may, but you shouldn't expect the compiler to accept it.
exit() returns void, which means that exit(EXIT_FAILURE) isn't a
scalar expression, so it can't be an operand of "||".

(Similarly, "return EXIT_FAILURE" can't be used here either, because
it's not an expression at all.)

Furthermore, fprintf() doesn't return an exit/failure result that you
can use in this context. It returns the number of characters printed
on success, or a negative value on an error. So you're going to
terminate the program only if fprintf() prints zero characters, and
continue if there's an error. I doubt that's what you want.

If you're really determined to use "||, you could do something like
this:

fprintf(...) >= 0 || (exit(EXIT_FAILURE), 0);

The left operand is true if and only if fprintf() succeeded. The
right operand uses the exit call as the left operand of a comma
operator (which is valid); the right operand as a whole yields the int
value 0, which is then discarded.

At this point, you should realize that C has the "if" keyword for very
good reasons.
The '||' operator will yield 1 if at least one operand is non-zero, in
other words if 'fprintf' fails, the 'exit' call is invoked and this
would be equal to:

if (fprintf(..) == 0)
exit();

It would be if exit() returned a scalar result.
 
E

Eric Sosman

Mark said:
So I also may write:

fprintf(...) || exit(EXIT_FAILURE);

No, because the type of the sub-expression `exit(...)'
is `void', and both operands of `||' must be scalars. You
could repair things by using the comma operator

fprintf(...) || (exit(EXIT_FAILURE), 0);
The '||' operator will yield 1 if at least one operand is non-zero, in
other words if 'fprintf' fails, [...]

If fprintf() fails, it returns a negative number -- and
since a negative number is non-zero, it means "true." The
only way fprintf() can return zero is if it generates no
output characters, that is, if it's `fprintf("")'.
 
D

David Thompson

Close, but not quite.

Both operands of "&&" have to be scalar. puts() returns an int, so it
can be used here; a call to a function returning void would be
invalid.

The "&&" operator yields 1 if both its operands are non-zero, 0
otherwise.
Right. (To be exact, compare not-equal to zero; that includes a
pointer being non-null.)
If the left operand is 0, the right operand is not evaluated, which is
what makes it act like an if statement. But using an if statement
would have been clearer.
Clear is in the eye of the beholder. I'm happy with both forms.
(This kind of thing is a fairly common idiom in shell scripts.)
And perl. And in those, it DOES 'return' whatever the right operand
does, not just 0/1. perl directly yields it; shell leaves it in $? .
Though in shell the sense is reversed: 0=true other=false.

Although it is probably most often used in the forms
something-failed && die
something-worked || die
which doesn't return/yield at all in the 'die' case.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top