- 论坛徽章:
- 0
|
关于C语言中的运算符++的问题,很烦躁。
干脆贴上自己看吧(C FAQ摘录)
Section 3. Expressions
3.1: Why doesn't this code:
a = 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 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. . 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& 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. .
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& 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++;
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. |
|