3.4. Strange operators
There are two operators left to mention which look decidedly odd. They
aren't ‘essential’, but from time to time do have their uses. Don't
ignore them completely. This is the only place where we describe them, so
our description includes what happens when they are mixed with pointer
types, which makes them look more complicated than they really are.
3.4.1. The ?: operator
Like playing the accordion, this is easier to demonstrate than to
describe.
expression1?expression2:expression3
If expression1 is true, then the result of the whole
expression is expression2, otherwise it is
expression3; depending on the value of expression1,
only one of them will be evaluated when the result is calculated.
The various combinations of types that are permitted for
expression2 and expression3 and, based on those, the
resulting type of the whole expression, are complicated. A lot of the
complexity is due to types and notions that we haven't seen so far. For
completeness they are described in detail below, but you'll have to put up
with a number of forward references.
The easiest case is when both expressions have arithmetic type (i.e.
integral or real). The usual arithmetic conversions are applied to find a
common type for both expressions and then that is the type of the result.
For example
a>b?1:3.5
contains a constant (1) of type int and
another (3.5) of type double . Applying the arithmetic
conversions gives a result of type double .
Other combinations are also permitted.
- If both operands are of compatible structure or union types, then that
is the type of the result.
- If both operands have
void type, then that is the type of
the result.
Various pointer types can be mixed.
- Both operands may be pointers to (possibly qualified)
compatible types.
- One operand may be a pointer and the other a null pointer
constant.
- One operand may be a pointer to an object or incomplete
type and the other a pointer to (possibly qualified)
void .
The type of the result when pointers are involved is derived in two
separate steps.
- If either of the operands is a pointer to a qualified type, the result
is a pointer to a type that is qualified by all the qualifiers of both
operands.
- If one operand is a null pointer constant, then the result has the
type of the other operand. If one operand is a pointer to void, the other
operand is converted to pointer to
void and that is the type
of the result. If both operands are pointers to compatible types
(ignoring any qualifiers) the the result has the composite
type.
Qualifiers, composite types and compatible types are all subjects
discussed later.
The shortest useful example that we can think of is this one, where the
string to be printed by printf is selected using this magical
operator.
#include <stdio.h>
#include <stdlib.h>
main(){
int i;
for(i=0; i <= 10; i++){
printf((i&1) ? "odd\n" : "even\n");
}
exit(EXIT_SUCCESS);
} Example 3.9
It's cute when you need it, but the first time that they see it most
people look very uncomfortable for a while, then recollect an urgent
appointment somewhere else.
After evaluating the first operand there is one of the sequence
points described in Chapter 8.
3.4.2. The comma operator
This wins the prize for ‘most obscure operator’. It allows a list
of expressions to be separated by commas:
expression-1,expression-2,expression-3,...,expression-n
and it goes on as long as you like. The expressions are
evaluated strictly left to right and their values discarded, except for
the last one, whose type and value determine the result of the overall
expression. Don't confuse this version of the comma with any of the other
uses C finds for it, especially the one that separates function arguments.
Here are a couple of examples of it in use.
#include <stdio.h>
#include <stdlib.h>
main(){
int i, j;
/* comma used - this loop has two counters */
for(i=0, j=0; i <= 10; i++, j = i*i){
printf("i %d j %d\n", i, j);
}
/*
* In this futile example, all but the last
* constant value is discarded.
* Note use of parentheses to force a comma
* expression in a function call.
*/
printf("Overall: %d\n", ("abc", 1.2e6, 4*3+2));
exit(EXIT_SUCCESS);
} Example 3.10
Unless you are feeling very adventurous, the comma operator is just as
well ignored. Be prepared to see it only on special occasions.
After evaluating each operand there is one of the sequence
points described in Chapter 8.
|