Section 3. Expressions 3.1: Why doesn't this code: a[i] = i++; work? A: The subexpression i++ causes a side effect -- it modifies i's value -- which leads to undefined behavior since i is also referenced elsewhere in the same expression, and there's no way to determine whether the reference (in a[i] on the left-hand side) should be to the old or the new value. (Note that although the language in K&R suggests that the behavior of this expression is unspecified, the C Standard makes the stronger statement that it is undefined -- see question 11.33.) References: K&R1 Sec. 2.12; K&R2 Sec. 2.12; ISO Sec. 6.3; H&S Sec. 7.12 pp. 227-9. 3.2: Under my compiler, the code int i = 7; printf("%d\n", i++ * i++); prints 49. Regardless of the order of evaluation, shouldn't it print 56? A: Although the postincrement and postdecrement operators ++ and -- perform their operations after yielding the former value, the implication of "after" is often misunderstood. It is *not* guaranteed that an increment or decrement is performed immediately after giving up the previous value and before any other part of the expression is evaluated. It is merely guaranteed that the update will be performed sometime before the expression is considered "finished" (before the next "sequence point," in ANSI C's terminology; see question 3.8). In the example, the compiler chose to multiply the previous value by itself and to perform both increments afterwards. The behavior of code which contains multiple, ambiguous side effects has always been undefined. (Loosely speaking, by "multiple, ambiguous side effects" we mean any combination of ++, --, =, +=, -=, etc. in a single expression which causes the same object either to be modified twice or modified and then inspected. This is a rough definition; see question 3.8 for a precise one, and question 11.33 for the meaning of "undefined.") Don't even try to find out how your compiler implements such things (contrary to the ill-advised exercises in many C textbooks); as K&R wisely point out, "if you don't know *how* they are done on various machines, that innocence may help to protect you." References: K&R1 Sec. 2.12 p. 50; K&R2 Sec. 2.12 p. 54; ISO Sec. 6.3; H&S Sec. 7.12 pp. 227-9; CT&P Sec. 3.7 p. 47; PCS Sec. 9.5 pp. 120-1. 3.3: I've experimented with the code int i = 3; i = i++; on several compilers. Some gave i the value 3, and some gave 4. Which compiler is correct? A: There is no correct answer; the expression is undefined. See questions 3.1, 3.8, 3.9, and 11.33. (Also, note that neither i++ nor ++i is the same as i+1. If you want to increment i, use i=i+1, i+=1, i++, or ++i, not some combination. See also question 3.12.) 3.3b: Here's a slick expression: a ^= b ^= a ^= b It swaps a and b without using a temporary. A: Not portably, it doesn't. It attempts to modify the variable a twice between sequence points, so its behavior is undefined. For example, it has been reported that when given the code int a = 123, b = 7654; a ^= b ^= a ^= b; the SCO Optimizing C compiler (icc) sets b to 123 and a to 0. See also questions 3.1, 3.8, 10.3, and 20.15c. 3.4: Can I use explicit parentheses to force the order of evaluation I want? Even if I don't, doesn't precedence dictate it? A: Not in general. Operator precedence and explicit parentheses impose only a partial ordering on the evaluation of an expression. In the expression f() + g() * h() although we know that the multiplication will happen before the addition, there is no telling which of the three functions will be called first. When you need to ensure the order of subexpression evaluation, you may need to use explicit temporary variables and separate statements. References: K&R1 Sec. 2.12 p. 49, Sec. A.7 p. 185; K&R2 Sec. 2.12 pp. 52-3, Sec. A.7 p. 200. 3.5: But what about the && and || operators? I see code like "while((c = getchar()) != EOF && c != '\n')" ... A: There is a special "short-circuiting" exception for those operators. The right-hand side is not evaluated if the left- hand side determines the outcome (i.e. is true for || or false for &&). Therefore, left-to-right evaluation is guaranteed, as it also is for the comma operator. Furthermore, all of these operators (along with ?:) introduce an extra internal sequence point (see question 3.8). References: K&R1 Sec. 2.6 p. 38, Secs. A7.11-12 pp. 190-1; K&R2 Sec. 2.6 p. 41, Secs. A7.14-15 pp. 207-8; ISO Sec. 6.3.13, Sec. 6.3.14, Sec. 6.3.15; H&S Sec. 7.7 pp. 217-8, Sec. 7.8 pp. 218-20, Sec. 7.12.1 p. 229; CT&P Sec. 3.7 pp. 46-7. 3.8: How can I understand these complex expressions? What's a "sequence point"? A: A sequence point is a point in time (at the end of the evaluation of a full expression, or at the ||, &&, ?:, or comma operators, or just before a function call) at which the dust has settled and all side effects are guaranteed to be complete. The ANSI/ISO C Standard states that Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored. The second sentence can be difficult to understand. It says that if an object is written to within a full expression, any and all accesses to it within the same expression must be for the purposes of computing the value to be written. This rule effectively constrains legal expressions to those in which the accesses demonstrably precede the modification. See also question 3.9 below. References: ISO Sec. 5.1.2.3, Sec. 6.3, Sec. 6.6, Annex C; Rationale Sec. 2.1.2.3; H&S Sec. 7.12.1 pp. 228-9. 3.9: So given a[i] = i++; we don't know which cell of a[] gets written to, but i does get incremented by one, right? A: *No*. Once an expression or program becomes undefined, *all* aspects of it become undefined. See questions 3.2, 3.3, 11.33, and 11.35. 3.12: If I'm not using the value of the expression, should I use i++ or ++i to increment a variable? A: Since the two forms differ only in the value yielded, they are entirely equivalent when only their side effect is needed. (However, the prefix form is preferred in C++.) See also question 3.3. References: K&R1 Sec. 2.8 p. 43; K&R2 Sec. 2.8 p. 47; ISO Sec. 6.3.2.4, Sec. 6.3.3.1; H&S Sec. 7.4.4 pp. 192-3, Sec. 7.5.8 pp. 199-200. 3.14: Why doesn't the code int a = 1000, b = 1000; long int c = a * b; work? A: Under C's integral promotion rules, the multiplication is carried out using int arithmetic, and the result may overflow or be truncated before being promoted and assigned to the long int left-hand side. Use an explicit cast to force long arithmetic: long int c = (long int)a * b; Note that (long int)(a * b) would *not* have the desired effect. A similar problem can arise when two integers are divided, with the result assigned to a floating-point variable; the solution is similar, too. References: K&R1 Sec. 2.7 p. 41; K&R2 Sec. 2.7 p. 44; ISO Sec. 6.2.1.5; H&S Sec. 6.3.4 p. 176; CT&P Sec. 3.9 pp. 49-50. 3.16: I have a complicated expression which I have to assign to one of two variables, depending on a condition. Can I use code like this? ((condition) ? a : b) = complicated_expression; A: No. The ?: operator, like most operators, yields a value, and you can't assign to a value. (In other words, ?: does not yield an "lvalue".) If you really want to, you can try something like *((condition) ? &a : &b) = complicated_expression; although this is admittedly not as pretty. References: ISO Sec. 6.3.15; H&S Sec. 7.1 pp. 179-180.