6.5.10 Bitwise AND operator
1238
Commentary
The rationale for performing these conversions is a general one that is not limited to the operands of the
702 operators
cause conversions
arithmetic operators.
C
++
The following conversion is presumably performed on the operands.
5.11p1
The usual arithmetic conversions are performed;
Common Implementations
If one of the operands is positive and has a type with lower rank than the other operand, it may be possible
to make use of processor instructions that operate on narrower width values. (Converting the operand to
the greater rank will cause it to be zero extended, which will cancel out any ones in the other operand.)
Unless both operands are known to be positive, there tend to be few opportunities for optimizing occurrences
of the
^
and
|
operators (because of the possibility that the result may be affected by an increase in value
representation bits).
Coding Guidelines
Unless both operands have the same type, which also has a rank at least equal to that of
int
, these conversions
will increase the number of value representation bits in one or both operands. Given that the binary
&
operator
is defined to work at the bit level, developers have to invest additional effort in considering the effects of the
usual arithmetic operands on the result of this operator.
A probabilistic argument could be used to argue that of all the bitwise operators the
&
operator has the
lowest probability of causing a fault through an unexpected increase in the number of value representation
bits. For instance, the probability of both operands having a negative value (needed for any additional bits to
be set in the result) is lower than the probability of one operand having a negative value (needed for a bit to
be set in the result of the ^ and | operators).
Unless the operands have a bit-set role, the guideline recommendation dealing with use of representation
945 bit-set role
information is applicable here.
569.1 represen-
tation in-
formation
using
1237
The result of the binary
&
operator is the bitwise AND of the operands (that is, each bit in the result is set if
and only if each of the corresponding bits in the converted operands is set).
Commentary
This information is usually expressed in tabular form.
0 1
0 0 0
1 0 1
Common Implementations
The Unisys A Series
[1423]
uses signed magnitude representation. If the operands have an unsigned type, the
bit used to represent the sign in signed types, which is present in the object representation on this processor,
does not take part in the binary
&
operation. If the operands have a signed type, the sign bit does take part in
the bitwise-AND operation.
Coding Guidelines
Although the result of the bitwise-AND operator is the common type derived from the usual arithmetic
conversions, for the purpose of these guideline recommendations its role is the same as that of its operands.
706 usual arith-
metic conver-
sions
1352 object
role
1238
92) Two objects may be adjacent in memory because they are adjacent elements of a larger array or adjacent
footnote
92
members of a structure with no padding between them, or because the implementation chose to place them
so, even though they are unrelated.
June 24, 2009 v 1.2
6.5.11 Bitwise exclusive OR operator
1240
Commentary
By definition elements of an array are contiguous and the standard specifies the relative order of members
array
contiguously
allocated set
of objects
526
structure
members
later compare later
1206
and their possible padding. Some implementations treat objects defined by different declarations in the same
structure
unnamed padding
1424
way as the declaration of members in a structure definition. For instance, assigning the same relative offsets
to objects local to a function definition as they would the equivalent member declarations in a structure type.
The issue of the layout of objects in storage is discussed elsewhere.
storage
layout
1354
This footnote lists all the cases where objects may be adjacent in memory.
C90
The C90 Standard did not discuss these object layout possibilities.
C
++
The C
++
Standard does not make these observations.
Other Languages
Most languages do not get involved in discussing this level of detail.
Common Implementations
Most implementations aim to minimize the amount of padding between objects. In many cases objects
defined in block scope are adjacent in memory to objects defined textually adjacent to them in the source
code.
1239
If prior invalid pointer operations (such as accesses outside array bounds) produced undefined behavior,
subsequent comparisons also produce undefined behavior.
Commentary
This describes a special case of undefined behavior. (It is called out because, in practice, it is more likely
to occur for values having pointer types than values having integer types.) Once undefined behavior has
occurred, any subsequent operation can also produce undefined behavior. The standard does not limit the
scope of undefined behaviors to operations involving operands that cause the initial occurrence.
Common Implementations
On many implementations the undefined behavior that occurs when additive operations, on values having an
integer type, overflow is symmetrical. That is, an overflow in one direction can be undone by an overflow
in the other direction (e.g.,
INT_MAX+2-2
produces the same result as
INT_MAX-2+2
). On implementations
for processors using a segmented architecture this symmetrical behavior may not occur, for values having
pointer
segmented
architecture
590
pointer types, because of internal details of how pointer arithmetic is handled on segment boundaries.
On some processors additive operations, on integer or pointer types, saturate. In this case the undefined
arithmetic
saturated
687
behavior is not symmetrical.
C90
The C90 Standard did not discuss this particular case of undefined behavior.
6.5.11 Bitwise exclusive OR operator
1240
exclusive-OR-expression:
AND-expression
exclusive-OR-expression ^ AND-expression
Commentary
The
^
operator can be replaced by a sequence of equivalent bitwise operators; for instance,
x ^ y
can be
written
(x & (~y)) | ((~x) & y)
. However, most processors contain a bitwise exclusive-OR instruction
and thus this operator is included in C. Being able to represent a bitwise operator using an equivalent
sequence of other operators is not necessarily an argument against that operator being included in C. It is
v 1.2 June 24, 2009
6.5.11 Bitwise exclusive OR operator
1242
possible to represent any boolean expression using a sequence of NAND (not and, e.g.,
!(x & y)
) operators;
for instance,
!x
becomes
x NAND x
,
x & y
becomes
(x NAND y) NAND (x NAND y)
, and so on. Although
this equivalence may be of practical use in hardware design (where use of mass-produced circuits performing
a single boolean operation can reduce costs), it is not applicable to software.
Other Languages
Languages that support bitwise operations usually support an exclusive-OR operator. The keyword
xor
is
sometimes used to denote this operator. The
^
character is used as a token to indicate pointer indirection in
Pascal and Ada.
Coding Guidelines
The exclusive-OR operator is not encountered in everyday life. There is no English word or phrase that
expresses its semantics. The everyday usage discussed in the subclause on the logical-OR operator is based
1256 logical-OR-
expression
syntax
on selecting between two alternatives (e.g., either one or the other which only deals with two of the four
possible combinations of operand values). Because of the lack of everyday usage, and because it does not
occur often within C source (compared with bitwise-AND and bitwise-OR (see Table 912.2)) it is to be
expected that developers will have to expend more effort in comprehending the consequences of this operator
when it is encountered in source code.
The greater cognitive cost associated with use of the exclusive-OR operator is not sufficient to recommend
against its use. Developers need to be able to make use of an alternative that has a lower cost. While the
behavior of the exclusive-OR operator can be obtained by various combinations of other bitwise operators, it
seems unlikely that the cost of comprehending any of these sequences of operators will be less than that of the
operator they replace. If the exclusive-OR operator appears within a more complicated boolean expression
it may be possible to rewrite that expression in an alternative form. Rewriting an expression can increase
1248.1 boolean
expression
minimize effort
the cognitive effort needed for readers to map between source code and the application domain (i.e., if the
conditions in the application domain are naturally expressed in terms of a sequence of operators that include
exclusive-OR). The cost/benefit of performing such a rewrite needs to be considered on a case by case basis.
Example
The
^
operator is equivalent to the binary
+
operator if its operands do not have any set bits in common. This
property can be used to perform simultaneous addition on eight digits represented in packed BCD
[698]
(i.e.,
four bits per digit).
1 int BCD_add(a, b)
2 {
3 int t1 = a + 0x06666666,
4 t2 = t1 + b,
5 t3 = t1 ^ b,
6 t4 = t2 ^ t3,
7 t5 = ~t4 & 0x11111110,
8 t6 = (t5 >> 2) | (t5 >> 3);
9 return t2 - t6;
10 }
Usage
The ^ operator represents 1.2% of all occurrences of bitwise operators in the visible source of the .c files.
Constraints
1241
Each of the operands shall have integer type.
Commentary
The discussion for the various subsections is the same as those for the bitwise AND operator.
1235 & binary
operand type
Semantics
June 24, 2009 v 1.2
6.5.12 Bitwise inclusive OR operator
1244
1242
The usual arithmetic conversions are performed on the operands.^
operands con-
verted
Commentary
The discussion in the various subsections is the same as that for the bitwise AND operator.
& binary
operands
converted
1236
1243
The result of the
^
operator is the bitwise exclusive OR of the operands (that is, each bit in the result is set if
and only if exactly one of the corresponding bits in the converted operands is set).
Commentary
This information is usually expressed in tabular form.
0 1
0 0 1
1 1 0
Common Implementations
The Unisys A Series
[1423]
uses signed magnitude representation. If the operands have an unsigned type, the
sign bit is not affected by the bitwise complement operator. If the operands have a signed type, the sign bit
does take part in the bitwise complement operation.
The bitwise exclusive-OR instruction is sometimes generated, by optimizers, to swap the contents of two
registers, without using a temporary register (as shown in the Example below).
Coding Guidelines
Although the result of the bitwise exclusive-OR operator is the common type derived from the usual arithmetic
conversions, for the purpose of these guideline recommendations its role is the same as that of its operands.
usual arith-
metic con-
versions
706
object
role
1352
Example
1 #define SWAP(x, y) (x=(x ^ y), y=(x ^ y), x=(x ^ y))
2 #define UNDEFINED_SWAP(x, y) (x ^= y ^= x ^= y) /
*
Requires right to left evaluation.
*
/
6.5.12 Bitwise inclusive OR operator
1244
inclusive-OR-
expression
syntax
inclusive-OR-expression:
exclusive-OR-expression
inclusive-OR-expression | exclusive-OR-expression
Commentary
The discussion on AND-expression is applicable here.
AND-
expression
syntax
1234
Coding Guidelines
The
|
and
||
operators differ from their corresponding AND operators in that the zero/nonzero status of
their result is always the same, even though the actual result values are likely to differ.
0x10 | 0x01 ⇒ 0x11
0x10 || 0x01 ⇒ 1
While it is possible to use either operators in a context where the result is compared against zero, the
guideline recommendation dealing with matching an operator to the role of its result still applies. The pattern
role
operand matching
1234
of operator context usage (see Table 1244.1) is similar to that of the two AND operators.
v 1.2 June 24, 2009
6.5.12 Bitwise inclusive OR operator
1247
Table 1244.1:
Occurrence of the
|
and
||
operator (as a percentage of all occurrences of each operator; the parenthesized value
is the percentage of all occurrences of the context that contains the operator). Based on the visible form of the .c files.
Context | ||
if control-expression 8.8 ( 0.7) 86.0 ( 6.9)
other contexts 90.7 (—) 11.9 (—)
while control-expression 0.3 ( 0.5) 1.9 ( 2.7)
for control-expression 0.0 ( 0.0) 0.3 ( 0.2)
switch control-expression 0.1 ( 0.3) 0.0 ( 0.0)
Constraints
1245
Each of the operands shall have integer type.
Commentary
The discussion for the various subsections is the same as those for the bitwise AND operator.
1235 & binary
operand type
Semantics
1246
The usual arithmetic conversions are performed on the operands.
Commentary
The discussion in the various subsections is the same as that for the bitwise exclusive-OR operator.
1242 ^
operands con-
verted
1247
The result of the
|
operator is the bitwise inclusive OR of the operands (that is, each bit in the result is set if
and only if at least one of the corresponding bits in the converted operands is set).
Commentary
This information is usually expressed in tabular form.
0 1
0 0 1
1 1 1
Common Implementations
The Unisys A Series
[1423]
uses signed magnitude representation. If the operands have an unsigned type, the
sign bit is not affected by the bitwise-OR operator. If the operands have a signed type, the sign bit does take
part in the bitwise-OR operation.
Numeric value
Occurrences
0 1632 64 100 128150 200 255
1
10
100
binary |
× decimal notation
•
hexadecimal notation
×
•
×
•
×
•
×
•
×
•
×
•
×
•
×
•
×
•
×
•
×
•
×
•
×
•
×
•
×
•
×
•
×
•
×
•
×
×
×
•
×
•
•
•
•
×
•
•
•
×
•
×
•
×
•
×
•
•
•
•
•••
××
•
•
×
••
•
×
•
••
•
•
•
•
•
×
•
•
•
•
•
•
•
•••
•
×
•
•••
•
×
• •
×
•
••
•
•• •
•
• ••
•
×
•
×
•
Figure 1244.1:
Number of
integer-constant
s having a given value appearing as the right operand of the bitwise-OR operator.
Based on the visible form of the .c files.
June 24, 2009 v 1.2
6.5.13 Logical AND operator
1248
Coding Guidelines
Although the result of the bitwise inclusive-OR operator is the common type derived from the usual arithmetic
conversions, for the purpose of these guideline recommendations its role is the same as that of its operands.
usual arith-
metic con-
versions
706
object
role
1352
6.5.13 Logical AND operator
1248
logical-AND-
expression
syntax
logical-AND-expression:
inclusive-OR-expression
logical-AND-expression && inclusive-OR-expression
Commentary
The relative precedence of the binary
&&
and
||
operators is the same as that of the binary
&
and
|
operators.
Other Languages
In many languages the logical-AND operator has higher precedence than the logical-OR operator. In a few
languages (Ada, Fortran which uses the keyword
.AND.
), they have the same precedence. Ada supports
two kinds of logical-AND operations:
and
and
and then
, the latter having the same semantics as the
bitwise
&
1234
logical-AND operator in C (short-circuit evaluation). These operators also have the same precedence as the
logical-OR and logical-XOR operators.
Coding Guidelines
The issue of swapping usages of the & and && operators is discussed elsewhere.
AND-
expression
syntax
1234
There are a number of techniques for simplifying expressions involving boolean values. One of the most
commonly used methods is the Karnaugh map.
[725]
(For equations involving more than five operands, the
Quine-McCluskey technique
[1388]
may be more applicable; this technique is also capable of being automated.),
while some people prefer algebraic manipulation (refer to Table 1248.1).
Although simplification may lead to an expression that requires less reader effort to comprehend as a
boolean expression, the resulting expression may require more effort to map to the model of the application
domain being used. For instance,
(A && (!B)) || ((!A) && B)
can be simplified to
A ^ B
(assuming
A
and
B
only take the values 0 and 1, otherwise another operation is required). However, while the use of
the exclusive-OR operator results in a visually simpler expression, developers have much less experience
dealing with it than the other bitwise and logical operators. There is also the possibility that, for instance, the
expression
(A && (!B))
occurs in other places within the source and has an easily-deduced meaning within
the framework of the application model.
Logical operators are part of mathematical logic. Does the human mind contain special circuitry that
mind
logical operator
performs this operation, just like most processors contain a group of transistors that perform this C operation?
Based on experimental observations, the answer would appear to be no. So how does the human mind handle
the logical-AND operation? One proposal is that people learn the rules of this operator by rote so that they
can later be retrieved from memory. The result of a logical operation is then obtained by evaluating each
operand’s condition to true or false and performing a table lookup using previously the learned logical-AND
table to find the result. Such an approach relies on short-term memory, and the limited capacity of short-term
memory offers one explanation of why people are poor at evaluating moderately complex logical operators
in their head. There is insufficient capacity to hold the values of the operands and the intermediate results.
The form of logical deduction that is needed in comprehending software rarely occurs in everyday life.
People’s ability to solve what appear to be problems in logic does not mean that the methods of boolean
mathematics are used. A number of other proposals have been made for how people handle logical problems
in everyday life. One is that the answers to the problems are simply remembered; after many years of life
experience, people accumulate a store of knowledge on how to deal with different situations.
Studies have found that belief in a particular statement being true can cause people to ignore its actual status
as a mathematical expression (i.e., people believe what they consider to be true rather than logically evaluating
v 1.2 June 24, 2009
6.5.13 Logical AND operator
1248
the true status of an expression). Estimating developers’ performance at handling logical expressions therefore
involves more than a model of how they process mathematical logic.
While minimizing the number of operands in a boolean expression may have appeal to mathematically
oriented developers, the result may be an expression that requires more effort to comprehend. It is not yet
possible to calculate the reader effort required to comprehend a particular boolean expression. For this reason
the following guideline recommendation relies on the judgment of those performing the code review.
Rev
1248.1
Boolean expressions shall be written in a form that helps minimize the effort needed by readers to
comprehend them.
A comment associated with the simplified expression can be notated in at least two ways: using equations
or by displaying the logic table. Few developers are sufficiently practiced at boolean algebra to be able to
fluently manipulate expressions; a lot of thought is usually required. A logic table highlights all combinations
of operands and, for small numbers of inputs, is easily accommodated in a comment.
Table 1248.1:
Various identities in boolean algebra expressed using the
||
and
&&
operators. Use of these identities may change
the number of times a particular expression is evaluated (which is sometimes the rationale for rewriting it). The relative order in
which expressions are evaluated may also change (e.g., when
A==1
and
B==0
in
(A && B) || (A && C)
the order of evaluation
is A⇒ B⇒ A⇒ C, but after use of the distributive law the order becomes A⇒ B⇒ C).
Relative Order Preserved Expression ⇒ Alternative Representation
Distributive laws
no (A && B) || (A && C) ⇒ A && (B || C)
no (A || B) && (A || C) ⇒ A || (B && C)
DeMorgan’s theorem
yes !(A || B) ⇒ (!A) && (!B)
yes !(A && B) ⇒ (!A) || (!B)
Other identities
yes A && ((!A) || B) ⇒ A && B
yes A || ((!A) && B) ⇒ A || B
The consensus identities
no (A && B) || ((!A) && C) || (B && C) ⇒ (A && B) || ((!A) && C))
yes (A && B) || (A && (!B) && C) ⇒ (A && B) || (A && C)
yes (A && B) || ((!A) && C) ⇒ ((!A) || B) && (A || C)
An expression containing a number of logical operators, each having operands whose evaluation involves
relational or equality operators, can always be written in a number of different ways, for instance:
1 if ((X < 4) && !(Y || (Z == 1)))
2 /
*
...
*
/
3
4 if ((Y != 0) && (Z != 0) && (X < 4))
5 /
*
...
*
/
6
7 if (!((X >= 4) || Y || (Z == 1)))
8 /
*
...
*
/
9
10 if (X < 4)
11 if (!(Y || (Z == 1)))
12 /
*
...
*
/
An example of complexity in an English sentence might be “Suppose five days after the day before yesterday
is Friday. What day of the week is tomorrow?” Whether the use of a less complex (i.e., having less cognitive
load) expression has greater cost/benefit than explicitly calling out the details of the calculation needs to be
determined on a case-by-case basis.
June 24, 2009 v 1.2
6.5.13 Logical AND operator
1250
A study by Feldman
[423]
found that the subjective difficulty of a concept (e.g., classifying colored polygons
of various sizes) was directly proportional to its boolean complexity (i.e., the length of the shortest logically
categoriza-
tion per-
formance
predicting
0
equivalent propositional formula).
Table 1248.2:
Common token pairs involving
&&
, or
||
(as a percentage of all occurrences of each token). Based on the visible
form of the
.c
files. Note: entries do not always sum to 100% because several token sequences that have very low percentages are
not listed.
Token Sequence
% Occurrence
of First Token
% Occurrence of
Second Token
Token Sequence
% Occurrence
of First Token
% Occurrence of
Second Token
identifier && 0.4 48.5 && defined 0.9 6.2
) || 0.9 42.7 || ! 11.3 6.0
identifier || 0.2 39.3 character-constant || 4.2 4.2
) && 1.1 34.9 character-constant && 5.3 3.3
|| defined 4.8 21.0 && ( 28.7 0.9
integer-constant || 0.3 12.4 || ( 29.7 0.6
integer-constant && 0.4 11.5 && identifier 53.9 0.5
&& ! 13.5 11.3 || identifier 51.8 0.3
Constraints
1249
Each of the operands shall have scalar type.&&
operand type
Commentary
The behavior is defined in terms of an implicit comparison against zero, an operation which is only defined
for operands having a scalar type in C.
C
++
5.14p1
The operands are both implicitly converted to type bool (clause 4).
Boolean conversions (4.12) covers conversions for all of the scalar types and is equivalent to the C behavior.
Other Languages
Languages that support boolean types usually require that the operands to their logical-AND operator have
boolean type.
Coding Guidelines
The discussion on the bitwise-AND operator is also applicable here, and the discussion on the comprehension
& binary
operand type
1235
of the controlling expression in an if statement is applicable to both operands.
if statement
controlling
expression
scalar type
1743
Table 1249.1:
Occurrence of logical operators having particular operand types (as a percentage of all occurrences of each
operator; an _ prefix indicates a literal operand). Based on the translated form of this book’s benchmark programs.
Left Operand Operator Right Operand % Left Operand Operator Right Operand %
int || int 87.7 _long || _long 2.2
int && int 73.9 int && ptr-to 2.2
other-types && other-types 12.8 int && char 1.8
other-types || other-types 8.4 int || _long 1.7
ptr-to && int 4.5 int && _int 1.3
char && int 2.3 ptr-to && ptr-to 1.1
Semantics
v 1.2 June 24, 2009
6.5.13 Logical AND operator
1250
1250
The && operator shall yield 1 if both of its operands compare unequal to 0; &&
operand com-
pare against 0
Commentary
The only relationship between the two operands is their appearance together in a logical-AND operation.
There is no benefit, from the implementations point of view, in performing the usual arithmetic conversions
or the integer promotions on each operand.
It is sometimes necessary to test a preliminary condition before the main condition can be tested. For
instance, it may be necessary to check that a pointer value is not null before dereferencing it. The test could
be performed using nested if statements, as in:
1 if (px != NULL)
2 if (px->m1 == 1)
More complex conditions are likely to involve the creation of a warren of nested
if
statements. The original
designers of the C language decided that it was worthwhile creating operators to provide a shorthand notation
(i.e., the logical-AND and logical-OR operators). In the preceding case use of one of these operators allows
both tests to be performed within a single conditional expression (e.g.,
if ((px != NULL) && (px->m1
== 1))
). The other advantage of this operator, over nested
if
statements, is in the creation of expressions
via the expansion of nested macro invocations. Generating nested
if
statements requires the use of braces
to ensure that any following
else
arms are associated with the intended
if
arm. Generating these braces
introduces additional complexities (at least another macro invocation in the source) that don’t occur when the
&& operator is used.
C
++
5.14p1
The result is true if both operands are true and false otherwise.
The difference in operand types is not applicable because C
++
defines equality to return
true
or
false
. The
difference in return value will not cause different behavior because
false
and
true
will be converted to
0
and 1 when required.
Other Languages
The mathematical use of this operator returns true if both operands are true. Languages that support a boolean
data type usually follow this convention.
Common Implementations
As discussed elsewhere, loading a value into a register often sets conditional flags as does a relational
1111 logical
negation
result is
operation comparing two values. This means that in many cases machine code to compare against zero need
1210 relational
operators
result value
not be generated, as in, the following condition:
1 if ((a == b) && (c < d))
which is likely to generate an instruction sequence of the form:
compare a with b
if not equal jump to else_or_endif
compare c with d
if greater than or equal to jump to else_or_endif
code for if arm
else_or_endif: rest of program
June 24, 2009 v 1.2
6.5.13 Logical AND operator
1253
Coding Guidelines
Should the operands always be explicitly compared against zero? When an operand is the result of a relational
or equality operator, such a comparison is likely to look very unusual:
1 if (((a == b) == 0) && ((c < d) == 0))
It is assumed that developers think about the operands in terms of boolean roles and the result of both the
relational and equality operators have a boolean role. In these cases another equality comparison is redundant.
When an operand does not have a boolean role, an explicit comparison against zero might be appropriate
(these issues are also discussed elsewhere).
!
equivalent to
1113
selection
statement
syntax
1739
1251
otherwise, it yields 0.
Commentary
That is, a value of zero having type int.
1252
The result has type int.&&
result type
Commentary
The rationale for this choice is the same as for relational operators.
relational
operators
result type
1211
C
++
5.14p2
The result is a bool.
The difference in result type will result in a difference of behavior if the result is the immediate operand of
the sizeof operator. Such usage is rare.
Other Languages
In languages that support a boolean type, the result of logical operators usually has a boolean type.
Common Implementations
If the result is immediately cast to another type, an implementation may choose to arrange that other type as
the result type; for instance, in:
1 float f(int ip)
2 {
3 return (ip > 0) && (ip < 10);
4 }
an implementation may choose to return
0.0
and
1.0
as the result of the expression evaluation, saving a cast
operation.
Coding Guidelines
The coding guideline issues are the same as those for the relational operators.
relational
operators
result type
1211
1253
Unlike the bitwise binary & operator, the && operator guarantees left-to-right evaluation;&&
evaluation order
Commentary
The left-to-right evaluation order of the
&&
operator is required; it is what makes it possible for the left
operand to verify a precondition for the evaluation of the right operand. There is no requirement that the
evaluation of the right operand, if it occurs, take place immediately after the evaluation of the left operand.
Coding Guidelines
This issue is covered by the guideline recommendation dealing with sequence points.
sequence
points
all orderings
give same value
187.1
v 1.2 June 24, 2009
6.5.13 Logical AND operator
1255
Example
In the following:
1 #include <stdio.h>
2
3 void f(void)
4 {
5 (printf("Hello ") && printf("World\n")) + printf("Goodbye\n");
6 }
possible output includes:
Hello World
Goodbye
and
Hello Goodbye
World
1254
there is a sequence point after the evaluation of the first operand. &&
sequence point
Commentary
Unlike the nested
if
statement form, there is no guaranteed sequence after the evaluation of the second
1250 &&
operand com-
pare against
0
operand, if it occurs.
C
++
5.14p2
All side effects of the first expression except for destruction of temporaries (12.2) happen before the second
expression is evaluated.
The possible difference in behavior is the same as for the function-call operator.
1025 function call
sequence point
Coding Guidelines
While the sequence point ensures that any side effects in the first operand have completed, relying on this
occurring creates a dependency within the expression that increases the effort needed to comprehend it. Some
of the issues involving side effects in expressions are discussed elsewhere.
941 object
modified once
between sequence
points
Example
1 #include <stdio.h>
2
3 extern int glob;
4
5 void f(void)
6 {
7 if (--glob && ++glob)
8 printf("The value of glob is neither 0 nor 1\n");
9 }
1255
If the first operand compares equal to 0, the second operand is not evaluated. &&
second operand
Commentary
An alternative way of looking at this operator is that x && y is equivalent to x ? (y?1:0) : 0.
June 24, 2009 v 1.2
6.5.14 Logical OR operator
1256
Common Implementations
This operand can be implemented, from the machine code generation point of view, as if a nested
if
construct
had been written.
Coding Guidelines
Some coding guideline documents prohibit the second operand containing side effects. The rationale is that
readers of the source may fail to notice that if the second operand is not evaluated any side effects it generates
will not occur. The majority of C’s binary operators (32 out of 34) always evaluate both of their operands.
Do developers make the incorrect assumption that the operands of all binary operators are always evaluated?
Your author thinks not. Many developers are aware that in some cases the
&&
operator is more efficient than
the & operator, because it only evaluates the second operand if the first is not sufficient to return a result.
Although many developers may be aware of the conditional evaluation of the second operand, some will
believe that both operands are evaluated. While a guideline recommendation against side effects in the
second operand may have a benefit for some developers, it potentially increases cost in that the alternative
construct used may require more effort to comprehend (e.g., the alternative described before). Given that the
alternative constructs that could be used are likely to require more effort to comprehend and the unknown
percentage of developers making incorrect assumptions about the evaluation of the operands, no guideline
recommendation is given.
Coverage testingcoverage testing
There are software coverage testing requirements that are specific to logical operators. Branch condition
decision testing involves the individual operands of logical operators. It requires that test cases be written to
exercise all combinations of operands. In:
1 if (A || (B && C))
it is necessary to verify that all combinations of
A
,
B
, and
C
, are evaluated. In the case of the condition
involving
A
,
B
, and
C
eight separate test cases are needed. For more complex conditions, the number of test
cases rapidly becomes impractical.
Modified condition decision testing requires that test cases be written to demonstrate that each operand
can independently affect the output of the decision. For the
if
statement above, Table 1255.1 shows the
possible conditions. Using modified condition, MC, coverage can significantly reduce the number of test
cases over branch condition, BC, coverage.
Table 1255.1:
Truth table showing how each operand of
(A || (B && C))
can affect its result. Case 1 and 2 show that
A
affects
the outcome; Case 3 shows that B affects the outcome; Case 3 and 4 shows that C affects the outcome.
Case A B C Result
1 FALSE FALSE TRUE FALSE
2 TRUE FALSE TRUE TRUE
3 FALSE TRUE TRUE TRUE
4 FALSE TRUE FALSE FALSE
The FAA requires
[1204]
that aviation software at Level A (the most critical, defined as that which could
prevent continued safe flight and landing of the aircraft) have the level of coverage specified by MC/DC
[103]
(DC decision coverage). This requirement has been criticized as not having a worthwhile cost (money
and time) and benefit (the number of errors found) ratio. An empirical evaluation of the HETE–2 satellite
software
[379]
looked at the faults found by various test methods and their costs. Logical operators can also
appear within expressions that are not a condition context. The preceding coverage requirements also hold in
these cases.
Horgan and London
[603]
describe an Open Source tool that measures various dataflow coverage metrics
for C source.
6.5.14 Logical OR operator
v 1.2 June 24, 2009
6.5.14 Logical OR operator
1258
1256
logical-OR-
expression
syntax
logical-OR-expression:
logical-AND-expression
logical-OR-expression || logical-AND-expression
Commentary
The discussion on the logical-AND operator is applicable here.
1248 logical-AND-
expression
syntax
Other Languages
Ada supports two kinds of logical-OR operations:
or
and
or else
. The latter has the same semantics as
the logical-OR operator in C (short-circuit evaluation). Support for an unsigned integer type was added in
Ada 95 and the definition of the logical operators was extended to perform bitwise operations when their
operands had this type.
Coding Guidelines
The issue of swapping usages of the | and || operators is discussed elsewhere.
1244 inclusive-OR-
expression
syntax
In English (and other languages) the word or is sometimes treated as having an exclusive rather than an
conditionals
conjunctive/disjunctive
inclusive meaning. For instance, “John has an M.D. or a Ph.D.” is likely to be interpreted in the exclusive
sense, while “John did not buy ice cream or chips” is likely to be interpreted in the inclusive sense (e.g., John
did not buy ice cream and did not buy chips); the exclusive sense supports surprising possibilities (e.g., John
buying ice cream and buying chips). A number of studies
[412]
have found that people make more mistakes
when answering questions that involve disjunctive (i.e., the logical-OR operator) relationships than when
answering questions that involve conjunctive (i.e., the logical-AND operator) relationships.
A study by Noveck, Chierchia, and Sylvestre
[1035]
(performed using French) found that the exclusive
interpretation occurs when a conclusion
QorR
is more informative or relevant and is prompted by an
implication (e.g., but not both).
Usage
Usage information is given elsewhere.
1248 logical-AND-
expression
syntax
Constraints
1257
Each of the operands shall have scalar type.
Commentary
The discussions in the various subsections of the logical-AND operator are applicable here.
1249 &&
operand type
C
++
5.15p1
The operands are both implicitly converted to bool (clause 4).
Boolean conversions (4.12) covers conversions for all of the scalar types and is equivalent to the C behavior.
Semantics
1258
The || operator shall yield 1 if either of its operands compare unequal to 0; ||
operand com-
pared against 0
Commentary
The discussion on the logical-AND operator is applicable here.
1250 &&
operand com-
pare against
0
C
++
5.15p1
June 24, 2009 v 1.2
6.5.15 Conditional operator
1264
It returns true if either of its operands is true, and false otherwise.
The difference in operand types is not applicable because C
++
defines equality to return
true
or
false
. The
difference in return value will not cause different behavior because
false
and
true
will be converted to
0
and 1 when required.
1259
otherwise, it yields 0.
Commentary
That is, a value of zero having type int.
1260
The result has type int.||
result type
Commentary
The discussion in the various subsections of the logical-AND operator are applicable here.
&&
result type
1252
C
++
5.15p2
The result is a bool.
The difference in result type will result in a difference of behavior if the result is the immediate operand of
the sizeof operator. Such usage is rare.
1261
Unlike the bitwise | operator, the || operator guarantees left-to-right evaluation;
Commentary
The discussion on the logical-AND operator is applicable here.
&&
evaluation order
1253
1262
there is a sequence point after the evaluation of the first operand.operator ||
sequence point
Commentary
The discussion on the logical-AND operator is applicable here.
&&
sequence point
1254
C
++
5.15p2
All side effects of the first expression except for destruction of temporaries (12.2) happen before the second
expression is evaluated.
The differences are discussed elsewhere.
&&
sequence point
1254
1263
If the first operand compares unequal to 0, the second operand is not evaluated.
Commentary
The discussion on the logical-AND operator is applicable here. An alternative way of looking at this operator
&&
second operand
1255
is that x || y is equivalent to x ? 1 : (y?1:0).
6.5.15 Conditional operator
1264
conditional-
expression
syntax
conditional-expression:
logical-OR-expression
logical-OR-expression ? expression : conditional-expression
v 1.2 June 24, 2009
6.5.15 Conditional operator
1264
Commentary
The conditional operator is not necessary in that it is possible to implement the functionality it provides
using other operators, statements, and sometimes preprocessing directives. However, C source code is
sometimes automatically generated and C includes a preprocessor. The automated generation C source code
is sometimes easier if conditional tests can be performed within an expression.
The second operand of a
conditional-expression
is
expression
which means that the
?
and
:
tokens
effectively act as brackets for the second expression; no parentheses are required. For instance,
a ? (b
, c) : d , e
can also be written as
a ? b , c : d , e
. The conditional operator associates to the
right.
955 associativity
operator
C
++
5.16
conditional-expression: logical-or-expression logical-or-expression ? expression :
assignment-expression
By supporting an
assignment-expression
as the third operand, C
++
enables the use of a
throw-expression
;
1288 assignment-
expression
syntax
for instance:
1 z = can_I_deal_with_this() ? 42 : throw X;
Source developed using a C
++
translator may contain uses of the conditional operator that are a constraint
violation if processed by a C translator. For instance, the expression
x?a:b=c
will need to be rewritten as
x?a:(b=c).
Other Languages
In some languages (e.g., Algol 68) statements can return values (they are treated as expressions). For such
languages the functionality of a conditional expression is provided by using an
if
statement (within an ex-
pression context). BCPL supports conditional expressions, using the syntax:
expression -> expression
, expression.
Common Implementations
MetaWare High C (in nonstandard mode), some versions of pcc, and gcc support the syntax:
conditional-expression:
logical-or-expression
logical-or-expression ? expression : assignment-expression
gcc
allows the second operand to be omitted. The expression
x ? : y
is treated as equivalent to
x ?
x : y
;
gcc
also supports compound expressions, which allow
if
statements to appear within an expression.
1313 compound
expression
Coding Guidelines
Most developers do not have sufficient experience with the conditional operator to be familiar with its
precedence level relative to other operators. Using parentheses removes the possibility of developers
mistakenly using the incorrect precedence.
943.1 expression
shall be parenthe-
sized
June 24, 2009 v 1.2
6.5.15 Conditional operator
1267
Table 1264.1:
Common token pairs involving
?
or
:
(to prevent confusion with the
:
punctuation token the operator form is
denoted by
?:
) (as a percentage of all occurrences of each token). Based on the visible form of the
.c
files. Note: entries do not
always sum to 100% because several token sequences that have very low percentages are not listed.
Token Sequence
% Occurrence
of First Token
% Occurrence of
Second Token
Token Sequence
% Occurrence
of First Token
% Occurrence of
Second Token
) ? 0.4 44.7 ? string-literal 20.1 1.5
identifier ? 0.1 44.0 ?: integer-constant 28.7 0.3
identifier ?: 0.1 40.3 ? integer-constant 20.2 0.2
integer-constant ?: 0.3 23.1 ? identifier 43.9 0.1
string-literal ?: 1.5 20.2 ?: identifier 35.9 0.1
) ?: 0.1 11.6 ?: ( 7.2 0.1
integer-constant ? 0.1 9.6 ? ( 6.2 0.1
?: string-literal 21.0 1.6
Constraints
1265
The first operand shall have scalar type.
Commentary
This is the same requirement as that given for a controlling expression in a selection statement and is specified
if statement
controlling
expression
scalar type
1743
for the same reasons.
C
++
5.16p1
The first expression is implicitly converted to bool (clause 4).
Boolean conversions (4.12) covers conversions for all of the scalar types and is equivalent to the C behavior.
Coding Guidelines
Many of the issues that apply to the controlling expression of an if statement are applicable here.
if statement
controlling
expression
scalar type
1743
1266
One of the following shall hold for the second and third operands:conditional
operator
second and third
operands
Commentary
The result of the conditional operator is one of its operands. The following list of constraints ensures that
conditional
operator
result
1277
the value of both operands can be operated on in the same way by subsequent operators (occurring in the
evaluation of an expression).
Table 1266.1:
Occurrence of the ternary
:
operator (denoted by the character sequence
?:
) having particular operand types (as a
percentage of all occurrences of each operator; an _ prefix indicates a literal operand). Based on the translated form of this book’s
benchmark programs.
Left Operand Operator Right Operand % Left Operand Operator Right Operand %
ptr-to ?: ptr-to 29.5 int ?: _int 5.7
other-types ?: other-types 12.1 _char ?: _char 3.4
_int ?: _int 10.4 unsigned int ?: unsigned int 2.2
int ?: int 10.0 unsigned short ?: unsigned short 1.2
void ?: void 9.4 signed int ?: _int 1.1
unsigned long ?: unsigned long 7.9 char ?: void 1.1
_int ?: int 6.0
1267
— both operands have arithmetic type;
v 1.2 June 24, 2009
6.5.15 Conditional operator
1272
Commentary
In this case it is possible to perform the usual arithmetic conversions to bring them to a common type.
Coding Guidelines
The guideline recommendation dealing with objects being used in a single role implies that the second and
1352.1 object
used in a sin-
gle role
third operands of a conditional operator should have the same role.
1268
— both operands have the same structure or union type; conditional
operator
structure/union
type
Commentary
While the structure or union types may be the same, the evaluation of the expressions denoting the two
operands may be completely different. However, a translator still has to ensure that the final result of both
operands, used by any subsequent operators, is held in the same processor location.
1269
— both operands have void type;
Commentary
In this case the conditional operator appears either as the left operand of the comma operator, the top-level
1313 comma
operator
syntax
operator of an expression statement, or as the second or third operand of another conditional operator in
these contexts. In either case alternative constructs are available. However, when dealing with macros that
may involve nested macro invocations, not having to be concerned with replacements that result in operands
having void type (invariably function calls) is a useful simplification.
1270
— both operands are pointers to qualified or unqualified versions of compatible types; conditional
expression
pointer to com-
patible types
Commentary
The discussion on the equality operators is applicable here.
1215 equality
operators
pointer to compati-
ble types
C
++
5.16p6
— The second and third operands have pointer type, or one has pointer type and the other is a null pointer
constant; pointer conversions (4.10) and qualification conversions (4.4) are performed to bring them to their
composite pointer type (5.9).
These conversions will not convert a pointer to an enumerated type to a pointer to integer type.
If one pointed-to type is an enumerated type and the other pointed-to type is the compatible integer type.
C permits such operands to occur in the same
conditional-expression
. C
++
does not. See pointer
subtraction for an example.
1159 subtraction
pointer operands
1271
— one operand is a pointer and the other is a null pointer constant; or
Commentary
The discussion on the equality operators is applicable here.
1217 equality
operators
null pointer
constant
1272
— 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.
Commentary
The discussion on the equality operators is applicable here.
1216 equality
operators
pointer to incom-
plete type
C
++
The C
++
Standard does not support implicit conversions from pointer to
void
to pointers to other types
(4.10p2). Therefore, this combination of operand types is not permitted.
June 24, 2009 v 1.2
6.5.15 Conditional operator
1277
1 int glob;
2 char
*
pc;
3 void
*
pv;
4
5 void f(void)
6 {
7 glob ? pc : pv; /
*
does not affect the conformance status of the program
*
/
8 // ill-formed
9 }
Semantics
1273
The first operand is evaluated;
Commentary
Much of the discussion on the evaluation of the controlling expression of an
if
statement is applicable here.
selection
statement
syntax
1739
Common Implementations
The only difference between evaluating this operand and a controlling expression is that in the former
controlling
expression
if statement
1740
case it is possible for more processor registers to be in use, holding results from the evaluation of other
subexpressions. (This likelihood of increased register pressure may result in spilling for processors with
register
spilling
209
relatively few registers— e.g., Intel x86.) However, whether the overall affect of using a conditional operator
is likely to be small, compared to an
if
statement, will depend on the characteristics of the expression and
optimizations performed.
1274
there is a sequence point after its evaluation.conditional
operator
sequence point
Commentary
Unlike the controlling expression in a selection statement, this operand is not a full expression, so this
selection
statement
syntax
1739
full ex-
pression
1712
specification of a sequence point is necessary to fully define the evaluation order. The discussion on the
logical-AND operator is applicable here.
&&
sequence point
1254
C
++
5.16p1
All side effects of the first expression except for destruction of temporaries (12.2) happen before the second or
third expression is evaluated.
The possible difference in behavior is the same as for the function-call operator.
function call
sequence point
1025
1275
The second operand is evaluated only if the first compares unequal to 0;conditional
operator
operand only
evaluated if
Commentary
Because the operand might not be evaluated, replacing a conditional operator by a function call, taking three
arguments, would not have the same semantics.
Coding Guidelines
The guideline discussion on the logical-AND operator is applicable here.
&&
second operand
1255
1276
the third operand is evaluated only if the first compares equal to 0;
Commentary
Either the second or the third operand is always evaluated, but never both.
v 1.2 June 24, 2009
6.5.15 Conditional operator
1277
1277
the result is the value of the second or third operand (whichever is evaluated), converted to the type described
conditional
operator
result
below.
93)
Commentary
The conversion, to a common compatible type, ensures that the result of evaluating either operand has the
same value representation.
Common Implementations
This places a requirement on the generated machine code to ensure that the result value is always left in the
same register or storage location. Subsequent machine instructions will reference this single location.
Coding Guidelines
The difference between an
if
statement and a conditional operator is that in the latter case there is a result that
can appear as the operand of another operator. Measurements of existing source suggest that developers have
significantly more experience dealing with
if
statements than conditional operators. Using a conditional
operator in a context in the visible source, where its result is not used (i.e., is not an operand to another
operator), fails to take advantage of a developer’s greater experience in dealing with
if
statements. However,
such usage is rare and a guideline recommending the use of an
if
statement in this case is not considered
worthwhile.
The conditional operator is not necessary for the writing of any program; it is always possible to rewrite
source so that it does not contain any conditional operators. Similarly, source can be rewritten, replacing
some
if
statements by conditional operators. How does the cost/benefit of using an
if
statement compare to
that of using a conditional operator? The two main issues are comprehension and maintenance:
•
From a reader’s perspective, the comprehension of a conditional operator may, or may not, require
more cognitive effort than comprehending an
if
statement. For instance, in the following example the
use of an
if
statement highlights the controlling expression while the single assignment highlights
that the array
a
is being modified (which needs to be deduced by reading two statements in the former
case);
1 if (x)
2 a[y]=0;
3 else
4 a[z]=0;
5
6 a[x ? y : z]=0;
When the expression being assigned to is complex, significant reader effort may be required to deduce
that the two complex expressions are the same. Use of a conditional operator removes the need to
make this comparison:
1 if (x)
2 a[complicated_expr]=y;
3 else
4 a[complicated_expr]=z;
5
6 a[complicated_expr]=(x ? y : z);
When an expression in a substatement, of an
if
statement, contains a reference to an object that also
occurs in the controlling expression, for instance:
1740 controlling
expression
if statement
1 if (x < 5)
2 a=10-x;
3 else
4 a=x;
5
6 a=(x < 5 ? 10-x : x);
June 24, 2009 v 1.2
6.5.15 Conditional operator
1279
readers may need to keep information about the condition in their minds when comprehending the
source in both cases (i.e., maximum cognitive load is very similar, if not the same). When an expression
in a substatement does not contain such a reference, readers do not need to evaluate information about
the conditional to comprehend that statement. Compared to selection statements the maximum
cognitive effort is likely to be less.
selection
statement
syntax
1739
•
In the following example a source modification requires that both
y
and
z
be assigned to
b
, instead of
a
, can be performed by editing one identifier in the case of the conditional operator usage, while the
if
statement usage requires two edits. However, a modification that required additional statements to
be executed, if x were true (or false), would require far less editing for the if statement usage.
1 if (x)
2 a=y;
3 else
4 a=z;
5
6 a = (x ? y : z);
if
statements occur in the visible source much more frequently than conditional operators. One reason is
that in many cases the
else
arm is not applicable (only 18% of
if
statements in the visible form of the
.c
files contain an
else
arm). Because on this usage pattern readers receive more practice with the use of
if
statements. Given this difference in familiarity, it is not surprising that conditional operators are used less
frequently than might be expected.
1278
If an attempt is made to modify the result of a conditional operator or to access it after the next sequence
conditional
operator
attempt to modify
point, the behavior is undefined.
Commentary
The discussion on the function-call operator result and its implementation details are applicable here.
function
result
attempt to modify
1007
C90
Wording to explicitly specify this undefined behavior is new in the C99 Standard.
C
++
The C
++
definition of lvalue is the same as C90, so this wording is not necessary in C
++
.
lvalue 721
Coding Guidelines
The code that needs to be written to generate this behavior is sufficiently obscure and unlikely to occur that
no guideline recommendation is given here.
Example
1 typedef struct {
2 int mem_1;
3 } A_S;
4 extern int glob;
5 extern A_S s_1, s_2;
6
7 void f(void)
8 {
9 int
*
p_l = &(((glob == 1) ? s_1 : s_2).mem_1);
10
11
*
p_l = 2; /
*
Undefined behavior.
*
/
12 }
v 1.2 June 24, 2009
6.5.15 Conditional operator
1282
1279
If both the second and third operands have arithmetic type, the result type that would be determined by the
conditional
operator
arithmetic result
usual arithmetic conversions, were they applied to those two operands, is the type of the result.
Commentary
There is no interaction between the types of the second and third operands and the first operand.
Other Languages
In Java:
[518]
15.25
If one of the operands is of type
T
where
T
is
byte
,
short
, or
char
, and the other operand is a constant expression
of type int whose value is representable in type T, then the type of the conditional expression is T.
Coding Guidelines
If developers use the analogy of an
if
statement when reasoning about the conditional operator, they are
1743 if statement
controlling
expression scalar
type
unlikely to consider the effects of applying the usual arithmetic conversions to the operands (although your
author is not aware of a case where a failure to take account of these conversions has resulted in a program
fault). However, this may be due to use of the conditional operator being comparatively rare (and these
guideline recommendations are not intended to cover rarely occurring construct).
0 guideline
recom-
mendations
selecting
For the purposes of these guideline recommendations, the role of the result is the same as the role of the
1234 role
operand matching
second and third operands.
1280
If both the operands have structure or union type, the result has that type.
Commentary
Both operands are required to have the same structure or union type.
1268 conditional
operator
structure/union
type
Common Implementations
The generated machine code may depend on what operation is performed on the result of the conditional
operator. For instance, a simple member access
(x ? s1:s2).m
may generate the same machine code as
if
(x ? s1.m : s2.m)
had been written. For more complicated cases, an implementation may load the
address of the two operands into a register for subsequent indirect accesses.
Coding Guidelines
The form
(x ? s1:s2).m
has the advantage, over
(x ? s1.m : s2.m)
, that a change to the member
selected only requires a single source modification (one of the two modifications needed in the latter form
may be overlooked). Also the former form requires less effort to recognize as always accessing member
m
.
(In the latter form the names of the two selected members needs to be checked.)
1281
If both operands have void type, the result has void type.
Commentary
This is one of the three cases where an operator does not return a value.
Coding Guidelines
If the operands have
void
type, the only affect on the output of the program is through the side effects of their
evaluation. Such usage embedded in the visible form of an expression (that is not automatically generated, or
the result of nested macro expansions) may be making assumptions about the order in which the operands of
an expression are evaluated. This issue is covered by a guideline recommendation.
187.1 sequence
points
all orderings
give same value
1282
If both the second and third operands are pointers or one is a null pointer constant and the other is a pointer,
conditional
operator
pointer to qual-
ified types
the result type is a pointer to a type qualified with all the type qualifiers of the types pointed-to by both
operands.
June 24, 2009 v 1.2
6.5.15 Conditional operator
1285
Commentary
Specifying that the result has all the qualifiers of both operands requires that a translator make worst-case
assumptions about subsequent operations. Type qualifiers on a pointed-to type do not affect the representation
or alignment requirements of the pointer type, which means subsequent operators are able to treat either
pointer
to quali-
fied/unqualified
types
559
operand in the same way.
In subsequent C sentences, in this C Standard paragraph, the term appropriately qualified refers to all the
type qualifiers specified here (as is shown by the EXAMPLE).
EXAMPLE
?: common
pointer type
1287
1283
Furthermore, if both operands are pointers to compatible types or to differently qualified versions of compatible
types, the result type is a pointer to an appropriately qualified version of the composite type;
Commentary
The specification for forming composite types lists a set of properties the result must have. The previous C
compos-
ite type
642
sentence ensured that the resulting pointed-to type has all the qualifiers of the two operands (two types that
are pointers to differently qualified compatible types are not compatible). The composite type will contain at
least as much, if not more, information than either of the types separately and will therefore be as restrictive
(with regard to type checking).
C90
Furthermore, if both operands are pointers to compatible types or differently qualified versions of a compatible
type, the result has the composite type;
The C90 wording did not specify that the appropriate qualifiers were added after forming the composite type.
In:
1 extern int glob;
2 const enum {E1, E2}
*
p_ce;
3 volatile int
*
p_vi;
4
5 void f(void)
6 {
7 glob =
*
((p_e != p_i) ? p_vi : p_ce);
8 }
the pointed-to type, which is the composite type of the
enum
and
int
types, is also qualified with
const
and
volatile.
1284
if one operand is a null pointer constant, the result has the type of the other operand;
Commentary
This places a requirement on the implementation to implicitly convert the operand that is a null pointer
constant to the type of the other operand (different pointer types may use different representations for the
null pointer). The discussion on the equality operators is applicable here.
null pointer
conversion yields
null pointer
750
equality
operators
null pointer
constant converted
1230
1285
otherwise, one operand is a pointer to
void
or a qualified version of
void
, in which case the result type is a
pointer to an appropriately qualified version of void.
Commentary
Although the null pointer constant may be represented by a value having a pointer to
void
type, the previous
null pointer
constant
748
C sentence takes precedence. The discussion on the equality operators is applicable here.
equality
operators
pointer to void
1231
C90
v 1.2 June 24, 2009
6.5.15 Conditional operator
1286
otherwise, one operand is a pointer to
void
or a qualified version of
void
, in which case the other operand is
converted to type pointer to void, and the result has that type.
C90 did not add any qualifies to the pointer to
void
type. In the case of the
const
qualifier this difference
would not have been noticeable (the resulting pointer type could not have been dereferenced without an
explicit cast to modify the pointed-to object). In the case of the
volatile
qualifier this difference may result
in values being accessed from registers in C90 while they will be accessed from storage in C99.
C
++
The C
++
Standard explicitly specifies the behavior for creating a composite pointer type (5.9p2) which is
returned in this case.
Coding Guidelines
The coding guideline discussion on the equality operators is applicable here.
1216 equality
operators
pointer to incom-
plete type
Example
1 const int
*
p_ci;
2 volatile int
*
p_vi;
3
4 void f(void)
5 {
6 const volatile int
*
p_cvi = ((p_vi != (void
*
)0) ?
7 p_ci :
8 (volatile void
*
)0); /
*
Not a null pointer constant.
*
/
9 }
1286
93) A conditional expression does not yield an lvalue. footnote
93
Commentary
This footnote points out a consequence of specifications appearing elsewhere in the standard.
725 lvalue
converted to
value
729 array
converted to
pointer
1 struct {
2 int m1[2];
3 } x, y;
4 int glob;
5
6 void f(void)
7 {
8 (glob ? x : y).m1; /
*
9
*
An array not a pointer to the first element. Converting the
10
*
array to a pointer to its first element requires an lvalue.
11
*
/
12 }
C
++
5.16p4
If the second and third operands are lvalues and have the same type, the result is of that type and is an lvalue.
5.16p5
Otherwise, the result is an rvalue.
Source developed using a C
++
translator may contain instances where the result of the conditional operator
appears in an rvalue context, which will cause a constraint violation if processed by a C translator.
June 24, 2009 v 1.2
6.5.16 Assignment operators
1288
1 extern int glob;
2
3 void f(void)
4 {
5 short loc_s;
6 int loc_i;
7
8 ((glob < 2) ? loc_i : glob) = 3; /
*
constraint violation
*
/
9 // conforming
10 ((glob > 2) ? loc_i : loc_s) = 3; // ill-formed
11 }
Common Implementations
Some implementations (e.g., gcc) support, as an extension, a conditional operator yielding an lvalue.
Example
Using indirection, it is possible to assign to objects appearing as operands of a conditional operator.
1 (x ? y : z) = 0; /
*
Constraint violation.
*
/
2
*
(x ? &y : &z) = 0; /
*
Strictly conforming.
*
/
1287
EXAMPLE The common type that results when the second and third operands are pointers is determined inEXAMPLE
?: common
pointer type
two independent stages. The appropriate qualifiers, for example, do not depend on whether the two pointers
have compatible types.
Given the declarations
const void
*
c_vp;
void
*
vp;
const int
*
c_ip;
volatile int
*
v_ip;
int
*
ip;
const char
*
c_cp;
the third column in the following table is the common type that is the result of a conditional expression in which
the first two columns are the second and third operands (in either order):
c_vp c_ip const void
*
v_ip 0 volatile int
*
c_ip v_ip const volatile int
*
vp c_cp const void
*
ip c_ip const int
*
vp ip void
*
Commentary
The effect is to maximize the number of type qualifiers and minimize the amount of type representation
information (i.e., pointer to void is a generic pointer type) in the common type.
C90
This example is new in C99.
6.5.16 Assignment operators
v 1.2 June 24, 2009
6.5.16 Assignment operators
1288
1288
assignment-
expression
syntax
assignment-expression:
conditional-expression
unary-expression assignment-operator assignment-expression
assignment-operator: one of
=
*
= /= %= += -= <<= >>= &= ^= |=
Commentary
The syntax is written so that these operators associate to the right. This means that in
x=y=z
,
z
is assigned to
955 associativity
operator
y
, which is then assigned to
x
. Defining assignment as an operator is consistent with the specification that it
returns a value. Its definition as an operator makes it possible for a full expression to contain more than one
1291 assignment
value of
assignment.
One benefit (to translator vendors) of compound assignment operators is that they remove the perceived
need for translators to perform certain kinds of optimization. One potential disadvantage to developers of
compound assignment operators is that they are likely to have the effect of causing vendors to write translators
that do not search for certain kinds of optimization. The underlying reason is the same in both cases. The
use of these operators affects the characteristics of the source that translator vendors expect to frequently
0 source code
characteristics
encounter (e.g., because developers are expected to write
x
*
=3
rather than
x=x
*
3
). Thus vendors don’t tune
optimizers to search for assignments in code that don’t make use of compound assignment operators (if this
usage is possible).
1 struct T {
2 struct fred
*
next;
3 /
*
...
*
/
4 } s_ptr;
5
6 s_ptr = s_ptr->next;
7 s_ptr ->= next; /
*
There is no ->= operator.
*
/
C
++
5.17
assignment-expression: conditional-expression logical-or-expression
assignment-operator assignment-expression throw-expression
For some types, a cast is an lvalue in C
++
.
1131 footnote
85
Other Languages
Most languages do not treat assignment as an operator, but as part of the syntax of the assignment statement.
Languages in the Algol family use
:=
as the assignment token. The token
/=
denotes the not equal operator
in some languages (e.g., Ada). Fortran contains the
ASSIGN
statement, which can be used to assign a label
to an object having type
INTEGER
. Perl (and BCPL) support assigning multiple values to multiple objects
within the same assignment (e.g.,
v1, v2, v3 = e1, e2, e3
). Algol 68 does not treat assignment as an
operator, but does treat compound assignment as operators. This results in
x +:= y := p -:= q := r
being parsed as (x +:= y) := (p -:= q) := r.
Common Implementations
The base document supported
=+
,
=
*
, and the reversed form of the other compound assignment operators.
[734]
1 base docu-
ment
June 24, 2009 v 1.2