# The New C Standard- P12

Chia sẻ: Thanh Cong | Ngày: | Loại File: PDF | Số trang:100

0
54
lượt xem
4

## The New C Standard- P12

Mô tả tài liệu

Tham khảo tài liệu 'the new c standard- p12', công nghệ thông tin, kỹ thuật lập trình phục vụ nhu cầu học tập, nghiên cứu và làm việc hiệu quả

Chủ đề:

Bình luận(0)

Lưu

## Nội dung Text: The New C Standard- P12

1. 6.5.10 Bitwise AND operator 1238 Commentary 702 operators The rationale for performing these conversions is a general one that is not limited to the operands of the cause conversions arithmetic operators. C++ The following conversion is presumably performed on the operands. The usual arithmetic conversions are performed; 5.11p1 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 deﬁned 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 569.1 represen- information is applicable here. 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 706 usual arith- conversions, for the purpose of these guideline recommendations its role is the same as that of its operands. 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
2. 1240 6.5.11 Bitwise exclusive OR operator array 526 Commentary contiguously allocated set By deﬁnition elements of an array are contiguous and the standard speciﬁes the relative order of members of objects structure 1206 and their possible padding. Some implementations treat objects deﬁned by different declarations in the same members later compare later way as the declaration of members in a structure deﬁnition. For instance, assigning the same relative offsets structure 1424 unnamed padding to objects local to a function deﬁnition as they would the equivalent member declarations in a structure type. storage 1354 layout The issue of the layout of objects in storage is discussed elsewhere. 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 deﬁned in block scope are adjacent in memory to objects deﬁned textually adjacent to them in the source code. If prior invalid pointer operations (such as accesses outside array bounds) produced undeﬁned behavior, 1239 subsequent comparisons also produce undeﬁned behavior. Commentary This describes a special case of undeﬁned 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 undeﬁned behavior has occurred, any subsequent operation can also produce undeﬁned behavior. The standard does not limit the scope of undeﬁned behaviors to operations involving operands that cause the initial occurrence. Common Implementations On many implementations the undeﬁned behavior that occurs when additive operations, on values having an integer type, overﬂow is symmetrical. That is, an overﬂow in one direction can be undone by an overﬂow in the other direction (e.g., INT_MAX+2-2 produces the same result as INT_MAX-2+2). On implementations pointer 590 segmented for processors using a segmented architecture this symmetrical behavior may not occur, for values having architecture pointer types, because of internal details of how pointer arithmetic is handled on segment boundaries. arithmetic 687 On some processors additive operations, on integer or pointer types, saturate. In this case the undeﬁned saturated behavior is not symmetrical. C90 The C90 Standard did not discuss this particular case of undeﬁned behavior. 6.5.11 Bitwise exclusive OR operator exclusive-OR-expression: 1240 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
3. 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 1256 logical-OR- expresses its semantics. The everyday usage discussed in the subclause on the logical-OR operator is based 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 sufﬁcient 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 1248.1 boolean it may be possible to rewrite that expression in an alternative form. Rewriting an expression can increase 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/beneﬁt 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 ﬁles. Constraints 1241 Each of the operands shall have integer type. Commentary 1235 & binary The discussion for the various subsections is the same as those for the bitwise AND operator. operand type Semantics June 24, 2009 v 1.2
4. 1244 6.5.12 Bitwise inclusive OR operator ^ The usual arithmetic conversions are performed on the operands. 1242 operands con- verted Commentary & binary 1236 operands The discussion in the various subsections is the same as that for the bitwise AND operator. converted The result of the ^ operator is the bitwise exclusive OR of the operands (that is, each bit in the result is set if 1243 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 usual arith- 706 metic con- conversions, for the purpose of these guideline recommendations its role is the same as that of its operands. versions object 1352 role 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 inclusive-OR- expression syntax 1244 inclusive-OR-expression: exclusive-OR-expression inclusive-OR-expression | exclusive-OR-expression Commentary AND- 1234 expression The discussion on AND-expression is applicable here. syntax 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 role 1234 guideline recommendation dealing with matching an operator to the role of its result still applies. The pattern operand matching of operator context usage (see Table 1244.1) is similar to that of the two AND operators. v 1.2 June 24, 2009
5. 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 ﬁles. 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 1235 & binary The discussion for the various subsections is the same as those for the bitwise AND operator. operand type Semantics 1246 The usual arithmetic conversions are performed on the operands. Commentary 1242 ^ The discussion in the various subsections is the same as that for the bitwise exclusive-OR operator. 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. binary | × × decimal notation • • hexadecimal notation 100 ×• • × • • • Occurrences × •• • • × × • • ×• • • • • × 10 ×• •× • •× × •• • • •× • • ×• • • ×• × ×• ••• • • ••• • • ••• • • • ×× × • • ×• • × × 1 •×• ×••••×× ••• × • • •• • ××• ×• •• • • •• •• •• ••× 0 16 32 64 100 128150 200 255 Numeric value Figure 1244.1: Number of integer-constants having a given value appearing as the right operand of the bitwise-OR operator. Based on the visible form of the .c ﬁles. June 24, 2009 v 1.2
6. 1248 6.5.13 Logical AND operator Coding Guidelines Although the result of the bitwise inclusive-OR operator is the common type derived from the usual arithmetic usual arith- 706 metic con- conversions, for the purpose of these guideline recommendations its role is the same as that of its operands. versions object 1352 role 6.5.13 Logical AND operator logical-AND- expression syntax 1248 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 bitwise 1234 two kinds of logical-AND operations: and and and then, the latter having the same semantics as the & 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 AND- 1234 expression The issue of swapping usages of the & and && operators is discussed elsewhere. syntax 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 ﬁve 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 simpliﬁcation 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 simpliﬁed 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. mind Logical operators are part of mathematical logic. Does the human mind contain special circuitry that 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 ﬁnd 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 insufﬁcient 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
7. 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 simpliﬁed expression can be notated in at least two ways: using equations or by displaying the logic table. Few developers are sufﬁciently practiced at boolean algebra to be able to ﬂuently 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 ﬁve 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/beneﬁt 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
8. 1250 6.5.13 Logical AND operator categoriza- 0 A study by Feldman[423] found that the subjective difﬁculty of a concept (e.g., classifying colored polygons tion per- of various sizes) was directly proportional to its boolean complexity (i.e., the length of the shortest logically formance predicting 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 ﬁles. Note: entries do not always sum to 100% because several token sequences that have very low percentages are not listed. Token Sequence % Occurrence % Occurrence of Token Sequence % Occurrence % Occurrence of of First Token Second Token of First Token Second Token identiﬁer && 0.4 48.5 && deﬁned 0.9 6.2 ) || 0.9 42.7 || ! 11.3 6.0 identiﬁer || 0.2 39.3 character-constant || 4.2 4.2 ) && 1.1 34.9 character-constant && 5.3 3.3 || deﬁned 4.8 21.0 && ( 28.7 0.9 integer-constant || 0.3 12.4 || ( 29.7 0.6 integer-constant && 0.4 11.5 && identiﬁer 53.9 0.5 && ! 13.5 11.3 || identiﬁer 51.8 0.3 Constraints && Each of the operands shall have scalar type. 1249 operand type Commentary The behavior is deﬁned in terms of an implicit comparison against zero, an operation which is only deﬁned for operands having a scalar type in C. C++ The operands are both implicitly converted to type bool (clause 4). 5.14p1 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 & binary 1235 operand type The discussion on the bitwise-AND operator is also applicable here, and the discussion on the comprehension if statement 1743 of the controlling expression in an if statement is applicable to both operands. controlling expression scalar type Table 1249.1: Occurrence of logical operators having particular operand types (as a percentage of all occurrences of each operator; an _ preﬁx 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
9. 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 beneﬁt, 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++ The result is true if both operands are true and false otherwise. 5.14p1 The difference in operand types is not applicable because C++ deﬁnes 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 1111 logical As discussed elsewhere, loading a value into a register often sets conditional ﬂags as does a relational negation result is operation comparing two values. This means that in many cases machine code to compare against zero need 1210 relational operators not be generated, as in, the following condition: result value 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
10. 1253 6.5.13 Logical AND operator 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 ! 1113 (these issues are also discussed elsewhere). equivalent to selection 1739 statement syntax otherwise, it yields 0. 1251 Commentary That is, a value of zero having type int. && The result has type int. 1252 result type Commentary relational 1211 operators The rationale for this choice is the same as for relational operators. result type C++ The result is a bool. 5.14p2 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 relational 1211 operators The coding guideline issues are the same as those for the relational operators. result type && Unlike the bitwise binary & operator, the && operator guarantees left-to-right evaluation; 1253 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. sequence 187.1 Coding Guidelines points This issue is covered by the guideline recommendation dealing with sequence points. all orderings give same value v 1.2 June 24, 2009
11. 6.5.13 Logical AND operator 1255 Example In the following: 1 #include 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 ﬁrst operand. && sequence point Commentary 1250 && operand com- Unlike the nested if statement form, there is no guaranteed sequence after the evaluation of the second pare against 0 operand, if it occurs. C++ All side effects of the ﬁrst expression except for destruction of temporaries (12.2) happen before the second 5.14p2 expression is evaluated. 1025 function call The possible difference in behavior is the same as for the function-call operator. sequence point Coding Guidelines While the sequence point ensures that any side effects in the ﬁrst operand have completed, relying on this occurring creates a dependency within the expression that increases the effort needed to comprehend it. Some 941 object of the issues involving side effects in expressions are discussed elsewhere. modiﬁed once between sequence points Example 1 #include 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 ﬁrst 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
12. 1256 6.5.14 Logical OR operator 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 efﬁcient than the & operator, because it only evaluates the second operand if the ﬁrst is not sufﬁcient 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 beneﬁt 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 testing Coverage testing There are software coverage testing requirements that are speciﬁc 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. Modiﬁed 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 modiﬁed condition, MC, coverage can signiﬁcantly 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, deﬁned as that which could prevent continued safe ﬂight and landing of the aircraft) have the level of coverage speciﬁed by MC/DC[103] (DC decision coverage). This requirement has been criticized as not having a worthwhile cost (money and time) and beneﬁt (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 dataﬂow coverage metrics for C source. 6.5.14 Logical OR operator v 1.2 June 24, 2009
13. 6.5.14 Logical OR operator 1258 logical-OR- expression 1256 syntax logical-OR-expression: logical-AND-expression logical-OR-expression || logical-AND-expression Commentary 1248 logical-AND- The discussion on the logical-AND operator is applicable here. 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 deﬁnition of the logical operators was extended to perform bitwise operations when their operands had this type. Coding Guidelines 1244 inclusive-OR- The issue of swapping usages of the | and || operators is discussed elsewhere. expression syntax In English (and other languages) the word or is sometimes treated as having an exclusive rather than an conditionals conjunctive/disjunct 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 1248 logical-AND- Usage information is given elsewhere. 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++ The operands are both implicitly converted to bool (clause 4). 5.15p1 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 1250 && operand com- The discussion on the logical-AND operator is applicable here. pare against 0 C++ 5.15p1 June 24, 2009 v 1.2
14. 1264 6.5.15 Conditional operator It returns true if either of its operands is true, and false otherwise. The difference in operand types is not applicable because C++ deﬁnes 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. otherwise, it yields 0. 1259 Commentary That is, a value of zero having type int. || The result has type int. 1260 result type Commentary && 1252 The discussion in the various subsections of the logical-AND operator are applicable here. result type C++ The result is a bool. 5.15p2 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. Unlike the bitwise | operator, the || operator guarantees left-to-right evaluation; 1261 Commentary && 1253 The discussion on the logical-AND operator is applicable here. evaluation order operator || there is a sequence point after the evaluation of the ﬁrst operand. 1262 sequence point Commentary && 1254 The discussion on the logical-AND operator is applicable here. sequence point C++ All side effects of the ﬁrst expression except for destruction of temporaries (12.2) happen before the second 5.15p2 expression is evaluated. && 1254 The differences are discussed elsewhere. sequence point If the ﬁrst operand compares unequal to 0, the second operand is not evaluated. 1263 Commentary && 1255 The discussion on the logical-AND operator is applicable here. An alternative way of looking at this operator second operand is that x || y is equivalent to x ? 1 : (y?1:0). 6.5.15 Conditional operator conditional- expression syntax 1264 conditional-expression: logical-OR-expression logical-OR-expression ? expression : conditional-expression v 1.2 June 24, 2009
15. 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++ conditional-expression: logical-or-expression logical-or-expression ? expression : 5.16 assignment-expression 1288 assignment- By supporting an assignment-expression as the third operand, C++ enables the use of a throw-expression; 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 ? 1313 compound x : y; gcc also supports compound expressions, which allow if statements to appear within an expression. expression Coding Guidelines Most developers do not have sufﬁcient experience with the conditional operator to be familiar with its precedence level relative to other operators. Using parentheses removes the possibility of developers 943.1 expression mistakenly using the incorrect precedence. shall be parenthe- sized June 24, 2009 v 1.2
16. 1267 6.5.15 Conditional operator 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 ﬁles. Note: entries do not always sum to 100% because several token sequences that have very low percentages are not listed. Token Sequence % Occurrence % Occurrence of Token Sequence % Occurrence % Occurrence of of First Token Second Token of First Token Second Token )? 0.4 44.7 ? string-literal 20.1 1.5 identiﬁer ? 0.1 44.0 ?: integer-constant 28.7 0.3 identiﬁer ?: 0.1 40.3 ? integer-constant 20.2 0.2 integer-constant ?: 0.3 23.1 ? identiﬁer 43.9 0.1 string-literal ?: 1.5 20.2 ?: identiﬁer 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 The ﬁrst operand shall have scalar type. 1265 Commentary if statement 1743 controlling expression This is the same requirement as that given for a controlling expression in a selection statement and is speciﬁed scalar type for the same reasons. C++ The ﬁrst expression is implicitly converted to bool (clause 4). 5.16p1 Boolean conversions (4.12) covers conversions for all of the scalar types and is equivalent to the C behavior. Coding Guidelines if statement 1743 controlling expression Many of the issues that apply to the controlling expression of an if statement are applicable here. scalar type conditional One of the following shall hold for the second and third operands: 1266 operator second and third Commentary operands conditional 1277 operator The result of the conditional operator is one of its operands. The following list of constraints ensures that result 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 _ preﬁx 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 — both operands have arithmetic type; 1267 v 1.2 June 24, 2009
17. 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 1352.1 object The guideline recommendation dealing with objects being used in a single role implies that the second and 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 Commentary structure/union type 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 ﬁnal result of both operands, used by any subsequent operators, is held in the same processor location. 1269 — both operands have void type; Commentary 1313 comma In this case the conditional operator appears either as the left operand of the comma operator, the top-level 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 simpliﬁcation. 1270 — both operands are pointers to qualiﬁed or unqualiﬁed versions of compatible types; conditional expression Commentary pointer to com- patible types The discussion on the equality operators is applicable here. 1215 equality operators pointer to compati- C++ ble types — The second and third operands have pointer type, or one has pointer type and the other is a null pointer 5.16p6 constant; pointer conversions (4.10) and qualiﬁcation 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 1159 subtraction subtraction for an example. pointer operands 1271 — one operand is a pointer and the other is a null pointer constant; or Commentary 1217 equality The discussion on the equality operators is applicable here. operators null pointer constant 1272 — one operand is a pointer to an object or incomplete type and the other is a pointer to a qualiﬁed or unqualiﬁed version of void. Commentary 1216 equality The discussion on the equality operators is applicable here. 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
18. 1277 6.5.15 Conditional operator 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 The ﬁrst operand is evaluated; 1273 Commentary selection 1739 statement syntax Much of the discussion on the evaluation of the controlling expression of an if statement is applicable here. Common Implementations controlling 1740 expression The only difference between evaluating this operand and a controlling expression is that in the former if statement case it is possible for more processor registers to be in use, holding results from the evaluation of other register 209 spilling subexpressions. (This likelihood of increased register pressure may result in spilling for processors with 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. conditional there is a sequence point after its evaluation. 1274 operator sequence point Commentary selection 1739 statement syntax Unlike the controlling expression in a selection statement, this operand is not a full expression, so this full ex- 1712 pression speciﬁcation of a sequence point is necessary to fully deﬁne the evaluation order. The discussion on the && 1254 sequence point logical-AND operator is applicable here. C++ All side effects of the ﬁrst expression except for destruction of temporaries (12.2) happen before the second or 5.16p1 third expression is evaluated. function call 1025 The possible difference in behavior is the same as for the function-call operator. sequence point conditional The second operand is evaluated only if the ﬁrst compares unequal to 0; 1275 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 && 1255 The guideline discussion on the logical-AND operator is applicable here. second operand the third operand is evaluated only if the ﬁrst compares equal to 0; 1276 Commentary Either the second or the third operand is always evaluated, but never both. v 1.2 June 24, 2009
19. 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 below.93) result 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 signiﬁcantly 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/beneﬁt 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 modiﬁed (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, signiﬁcant 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 1740 controlling occurs in the controlling expression, for instance: 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
20. 1279 6.5.15 Conditional operator 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 selection 1739 statement syntax cognitive effort is likely to be less. • In the following example a source modiﬁcation requires that both y and z be assigned to b, instead of a, can be performed by editing one identiﬁer in the case of the conditional operator usage, while the if statement usage requires two edits. However, a modiﬁcation 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 ﬁles 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. conditional If an attempt is made to modify the result of a conditional operator or to access it after the next sequence 1278 operator attempt to modify point, the behavior is undeﬁned. Commentary function 1007 result attempt to modify The discussion on the function-call operator result and its implementation details are applicable here. C90 Wording to explicitly specify this undeﬁned behavior is new in the C99 Standard. C++ lvalue 721 The C++ deﬁnition of lvalue is the same as C90, so this wording is not necessary in C++. Coding Guidelines The code that needs to be written to generate this behavior is sufﬁciently 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