Comma Operator Question

S

Shawn Odekirk

Some code I have inherited contains a macro like the following:

#define setState(state, newstate) \
(state >= newstate) ? \
(fprintf(stderr, "Illegal state\n"), TRUE) : \
(state = newstate, FALSE)

This macro is called like this:

setState(state, ST_Used);

I understand that the macro prints an error message unless the new
state is greater than the old state. I don't understand the TRUE and
FALSE bits.
It looks like the comma operator causes the macro to evaluate to TRUE
or FALSE. Am I right?
What is the result of the macro evaluating to TRUE or FALSE?
It's hard to know what the original programmer was thinking, but could
he have been intending the macro to be used as a condition?

if (setState(state, ST_Used))
do something...

Any thoughts about why the comma operator is being used will be
appreciated.

Thanks,
Shawn
 
T

Trevor Pearson

Some code I have inherited contains a macro like the following:

#define setState(state, newstate) \
(state >= newstate) ? \
(fprintf(stderr, "Illegal state\n"), TRUE) : \
(state = newstate, FALSE)

This macro is called like this:

setState(state, ST_Used);

I understand that the macro prints an error message unless the new
state is greater than the old state. I don't understand the TRUE and
FALSE bits.
It looks like the comma operator causes the macro to evaluate to TRUE
or FALSE. Am I right?
No.
The comma separates two arguments to a macro called state and newstate
The second line is a comparison which evaluates to true if state is
greater than or equal to newstate otherwise it is false
The macro is built on a old device called a tri-graph which works like
this
<some expresion> ? statement1 : statement2

The expresion returns a value (true or false) and if it is true
statement 1 is executed. If it is false statement 2 is executed.

All statements return a value whether or not you use it. in a comma
seperated list of statements the result of the statement is the result of
the last statement so the original programmer is 'returning' either true
or false most probably to use in conditional tests as you suggest below.

What is the result of the macro evaluating to TRUE or FALSE?
It's hard to know what the original programmer was thinking, but could
he have been intending the macro to be used as a condition?

if (setState(state, ST_Used))
do something...

Any thoughts about why the comma operator is being used will be
appreciated.

The comma is used here to make sure the return value is of the correct
type. Any statements seperated by a comma are executed in order but the
return value is the value of the last statement and also of that type.

The macro would work with any numerical type but because of the
comma returns a boolean very useful if you want to do ---
/* snipity snip*/
boolean flag;

..
..
..


flag=setState(var1, var5);


Thanks,
Shawn

P.S. False is '0', true= non zero result

OK
Trevor
 
R

red floyd

Some code I have inherited contains a macro like the following:

#define setState(state, newstate) \
(state >= newstate) ? \
(fprintf(stderr, "Illegal state\n"), TRUE) : \
(state = newstate, FALSE)

This macro is called like this:

setState(state, ST_Used);

I understand that the macro prints an error message unless the new
state is greater than the old state. I don't understand the TRUE and
FALSE bits.
It looks like the comma operator causes the macro to evaluate to TRUE
or FALSE. Am I right?
What is the result of the macro evaluating to TRUE or FALSE?
It's hard to know what the original programmer was thinking, but could
he have been intending the macro to be used as a condition?

if (setState(state, ST_Used))
do something...

Any thoughts about why the comma operator is being used will be
appreciated.

1. Probably so that it can be used in an if or while statement

2. TRUE, FALSE, and the type of state are undefined in the snippet,
if the type of "state" is not an int, or freely convertible to int,
then some compilers may generate an error or warning (disclaimer, I
don't have a copy of the standard). I believe that both operands of a
?: operator must have the same type (but I may be wrong).
 
B

Barry Schwarz

Some code I have inherited contains a macro like the following:

#define setState(state, newstate) \
(state >= newstate) ? \
(fprintf(stderr, "Illegal state\n"), TRUE) : \
(state = newstate, FALSE)

This macro is called like this:

setState(state, ST_Used);

I understand that the macro prints an error message unless the new

No, the macro doesn't print anything.
state is greater than the old state. I don't understand the TRUE and
FALSE bits.
It looks like the comma operator causes the macro to evaluate to TRUE
or FALSE. Am I right?

Macros are inputs to the preprocessor. The only thing they evaluate
to is the substituted text which is then passed to the compiler. When
used as in your example, the macro evaluates to
(state >= ST_Used) ?
(fprintf(...), TRUE) :
(state = ST_Used, FALSE);

TRUE and FALSE are probably also macros and should be defined prior to
setState.

Now, if this code is ever executed, then one of two things will
happen:

The string will be sent to stderr and the expression will evaluate
to TRUE (which I would expect to be 1).

The value in state will be changed and the expression will
evaluate to FALSE (which I would expect to be 0).
What is the result of the macro evaluating to TRUE or FALSE?
It's hard to know what the original programmer was thinking, but could
he have been intending the macro to be used as a condition?

if (setState(state, ST_Used))
do something...

A reasonable assumption. Not necessarily true but reasonable. If you
have reason to believe the original author was competent, it might
even be probable. But then we have to ask why he didn't leave any
documentation so you wouldn't have to guess. Do you see any code that
looks like this? How often does he invoke the macro?
Any thoughts about why the comma operator is being used will be
appreciated.

Since the macro could have just as easily evaluate to an if-then-else,
my *guess* is that he thought he was being clever. If you really need
to know, you could ask in one of the ESP newsgroups but here it is
only a guess.


<<Remove the del for email>>
 
K

Keith Thompson

Trevor Pearson said:

Yes, he's right.
The comma separates two arguments to a macro called state and newstate

Yes, the comma on the first line (the one starting with "#define")
separates the two parameters of the setState macro, but that's not the
comma operator the OP was asking about.
The second line is a comparison which evaluates to true if state is
greater than or equal to newstate otherwise it is false
Right.

The macro is built on a old device called a tri-graph which works like
this
<some expresion> ? statement1 : statement2

That's a trinary expression, or a conditional expression. (A trigraph
is something else entirely.) All three operands are expressions, not
statements. The distinction between statements and expressions is
very important.
The expresion returns a value (true or false) and if it is true
statement 1 is executed. If it is false statement 2 is executed.

Replace "statement" with "expression", and "executed" with
"evaluated", and that's essentially correct.
All statements return a value whether or not you use it. in a comma
seperated list of statements the result of the statement is the result of
the last statement so the original programmer is 'returning' either true
or false most probably to use in conditional tests as you suggest below.

Expressions return (or, more accurately, yield) values; statements do
not. Statements are not separated by commas.

In the third and fourth lines of the macro definition (the second and
third operands of the "?:" operator), the comma is being used as a
comma operator. This operator takes two operands. The left operand
is evaluated (presumably for side effects) and its result is
discarded, then the right operand is evaluted and its result becomes
the result of the comma operator.

The ?: operator is analagous to an if-else statement, and a comma
operator is analagous to a pair of consecutive statements; the
difference is that the operators apply to expressions, not to
statements. These operators are commonly used in definitions of
macros that are intended to be used as expressions (which can't
contain statements).

Here's the macro definition again:

#define setState(state, newstate) \
(state >= newstate) ? \
(fprintf(stderr, "Illegal state\n"), TRUE) : \
(state = newstate, FALSE)

though to avoid possible operator precedence problems I'd probably
write it like this:

#define setState(state, newstate) \
(((state) >= (newstate)) ? \
(fprintf(stderr, "Illegal state\n"), TRUE) : \
((state) = (newstate), FALSE))

If this were written as a function, it might look like this:

int setState(int *state, int newstate)
{
if (*state >= newstate) {
fprintf(stderr, "Illegal state\n");
return TRUE;
}
else {
*state = newstate;
return FALSE;
}
}

In the macro, state is modified, so I made it a pointer argument in
the function.

Presumably it was implemented as a macro to avoid the overhead of a
function call. That's not always a good tradeoff. Many optimizing
compilers support inline functions, either explicitly or implicitly.

All this assumes appropriate definitions for FALSE and TRUE.

If the macro is invoked, or the function is called, in a context like

setState(state, ST_Used);

the result (either FALSE or TRUE) is discarded. This may or may not
be a bad idea (it can mask errors).
 
A

Artie Gold

Keith said:
That's a trinary expression, or a conditional expression. (A trigraph
is something else entirely.) All three operands are expressions, not
statements. The distinction between statements and expressions is
very important.

Nit: It's a *ternary* expression.HTH,
--ag
 
K

Keith Thompson

Artie Gold said:
Nit: It's a *ternary* expression.
HTH,

The standard doesn't refer to it as either trinary or ternary (it does
use the word "ternary" a couple of times, but not in reference to the
conditional operator). But yes, "ternary" is probably a better term.
Thanks.

The standard refers to operators that take two operands as "binary
operators". Is there a word that is to "binary" as "ternary" is to
"trinary"?
 
D

Dario

Keith Thompson said:
That's a trinary expression, or a conditional expression. (A trigraph
is something else entirely.) All three operands are expressions, not
statements. The distinction between statements and expressions is
very important.


Replace "statement" with "expression", and "executed" with
"evaluated", and that's essentially correct.

Something that evaluates to void is a expression ?
because i tried compiling this code and i succeded without
warning

void f0()
{
}
void f1()
{
}
//

<expression> ? f0() : f1();
 
E

Eric Sosman

Dario said:
Something that evaluates to void is a expression ?
because i tried compiling this code and i succeded without
warning

void f0()
{
}
void f1()
{
}
//

<expression> ? f0() : f1();

Every C expression has a type. Most C expressions
also produce values, but expressions of type `void' are
an exception: the `void' type cannot express any value.
An expression of `void' type, even though it produces no
value, is an expression nonetheless.

`void' is, obviously, a peculiar beast. It is a type,
but cannot express values. It is a type, yet one cannot
create objects of that type. It is an incomplete type
that cannot be completed. Given all these oddities one
might wonder why `void' should be considered a "type" at
all, and many languages other than C do perfectly well
without a `void'-like notion at all. But such languages
usually have other features that make `void' unnecessary:
they may distinguish between "function" and "subroutine,"
or they may allow an expression to produce a special value
like "nil." C lacks "nil" and has no "subroutine" or
"procedure" or "call" statement, and it seems to me this
is why C has `void'.
 
I

Irrwahn Grausewitz

Something that evaluates to void is a expression ?

Yes, of course; random examples: (void)666, free(NULL), ...
because i tried compiling this code and i succeded without
warning

void f0()
{
}
void f1()
{
}
//

<expression> ? f0() : f1();

(Assuming <expression> is an actual expression that meets the
requirements for a logical-OR-expression, and the last line appears
in a function body:) A compiler diagnostic is not required, since
this is perfectly valid C code, which is essentially equivalent to:

if ( <expression> )
f0();
else
f1();

In other words, the second or third operand of the conditional
operator is evaluated only for its side effects, not for its
value.

Albeit, if you try to assign the non-existent value of the result
to an object, you invoke undefined behaviour:

int i = ( 6 * 9 == 42 ) ? f0() : f1(); /* WRONG! */

Regards
 
I

Irrwahn Grausewitz

I believe that both operands of a
?: operator must have the same type

Not necessarily, consider:

ISO/IEC 9899:1999
6.5.15 Conditional operator

Syntax
1 conditional-expression:
logical-OR-expression
logical-OR-expression ? expression : conditional-expression

Constraints
2 The first operand shall have scalar type.
3 One of the following shall hold for the second and third operands:
- both operands have arithmetic type;
- both operands have the same structure or union type;
- both operands have void type;
- both operands are pointers to qualified or unqualified versions
of compatible types;
- one operand is a pointer and the other is a null pointer
constant;
or
- one operand is a pointer to an object or incomplete type and the
other is a pointer to a qualified or unqualified version of void.

Regards
 
D

Dave Thompson

Artie Gold said:
Keith said:
[use of ?:]'s a trinary expression, or a conditional expression. <snip>
Nit: It's a *ternary* expression.
The standard doesn't refer to it as either trinary or ternary (it does
use the word "ternary" a couple of times, but not in reference to the
conditional operator). But yes, "ternary" is probably a better term.
Thanks.

The standard refers to operators that take two operands as "binary
operators". Is there a word that is to "binary" as "ternary" is to
"trinary"?

APL called 1- and 2-operand operators monadic and dyadic, both I
believe from Greek. Which has the advantage of leaving binary to mean
base-2 arithmetic, and possibly also Boolean logic but C uses bitwise
for that. APL classically also used niladic for 0-operands, though I
have recently been told that is inconsistent and anadic is better.

- David.Thompson1 at worldnet.att.net
 

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

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,228
Members
46,818
Latest member
SapanaCarpetStudio

Latest Threads

Top