📄 faqcatee08.html
字号:
<li>at a function call(after the evaluation of all the arguments,andjust before the actual call).</UL></p><p>TheStandard states that<blockquote>Between the previous and next sequence pointan object shall have its stored value modifiedat most once by the evaluation of an expression.Furthermore,the prior value shall be accessed onlyto determine the value to be stored.</blockquote></p><p>These two rather opaque sentencessay several things.First,they talk about operations bounded bythe``previous and next sequence points'';such operationsusually correspond tofull expressions.(In an expression statement,the ``next sequence point''isusuallyat the terminating semicolon,and the ``previous sequence point''isat the end of the previousstatement.An expression may also contain intermediatesequence points,as listed above.)</p><p>The first sentence rules out both the examples<pre> i++ * i++</pre>and<pre> i = i++</pre>from questions <a href="faqcatee08.html?sec=expr#evalorder2">3.2</a>and <a href="faqcatee08.html?sec=expr#ieqiplusplus">3.3</a>--in both cases,<TT>i</TT> has its value modified twice within the expression,i.e. between sequence points.(If we were to write a similar expressionwhichdidhave an internal sequence point,such as<pre> i++ && i++</pre>it <em>would</em> be well-defined,if questionably useful.)</p><p>The second sentencecan bequitedifficult to understand.It turns out that it disallows code like<pre> a[i] = i++</pre>from question <a href="faqcatee08.html?sec=expr#evalorder1">3.1</a>.(Actually, the other expressions we've been discussingare in violation of the second sentence, as well.)To see why,let's first look more carefullyat what the Standard is trying to allow and disallow.</p><p>Clearly,expressions like<pre> a = b</pre>and<pre> c = d + e</pre>which readsome values and use them to write others,are well-defined andlegal.Clearly,<a href="../../expr/fn16.html" rel=subdocument>[footnote]</a>expressions like<pre> i = i++</pre>which modify the same value twiceare abominationswhich needn't be allowed(or in any case,needn't be well-defined,i.e. we don't have to figure out a way to say what they do,and compilers don't have to support them).Expressionslike theseare disallowed by the first sentence.</p><p>It's also clear<a href="../../expr/fn16.html" rel=subdocument>[footnote]</a>that we'd like to disallow expressions like<pre> a[i] = i++</pre>which modify <TT>i</TT> <em>and</em> use it along the way,but not disallow expressions like<pre> i = i + 1</pre>whichuse and modify <TT>i</TT>but only modify itlaterwhen it's reasonably easy to ensurethat the final store of the final value(into <TT>i</TT>, in this case)doesn't interfere withtheearlieraccesses.</p><p>And that'swhat the second sentence says:if an object is written to within a full expression,anyand allaccesses to it within the same expressionmust bedirectly involved in the computation ofthe value to be written.This rule effectively constrains legal expressionsto those in which the accesses demonstrably precedethemodification.For example,the old standby<TT>i = i + 1</TT> isallowed,because the access of <TT>i</TT> is used to determine <TT>i</TT>'s final value.The example<pre> a[i] = i++</pre>is disallowed because one of the accessesof <TT>i</TT>(the one in <TT>a[i]</TT>)has nothing to dowith the value which ends up being stored in <TT>i</TT>(which happens over in <TT>i++</TT>),and so there's no good way todefine--either for our understandingor the compiler's--whether the access should take place before or after the incremented value is stored.Since there's no good way to define it,the Standard declares that it is undefined,and that portable programssimply must not use such constructs.</p><p>See alsoquestions <a href="faqcatee08.html?sec=expr#evalorder4">3.9</a> and <a href="faqcatee08.html?sec=expr#confused">3.11</a>.</p><p>References:ISO Sec. 5.1.2.3, Sec. 6.3, Sec. 6.6, Annex C<br>Rationale Sec. 2.1.2.3<br>H&S Sec. 7.12.1 pp. 228-9<hr><hr><hr><a name="evalorder4"><h1>comp.lang.c FAQ list<font color=blue>·</font><a href="../../expr/evalorder4.html"><!-- qtag -->Question 3.9</a></h1><p><font face=Helvetica size=8 color=blue><b>Q:</b></font>Soif I write<pre>a[i] = i++;</pre>and I don't carewhich cell of <TT>a[]</TT> gets written to,the code is fine,and <TT>i</TT> getsincremented by one,right?</p><p><hr><p><font face=Helvetica size=8 color=blue><b>A:</b></font>Not necessarily!For one thing,if you don't care which cell of <TT>a[]</TT> gets written to,why write code which seems to write to <TT>a[]</TT> at all?More significantly,oncean expression or program becomes undefined,<em>all</em> aspects of it become undefined.When an undefined expression has(apparently)two plausible interpretations,do not mislead yourself by imaginingthat the compiler will choose one or the other.The Standard does not require thata compiler make an obvious choice,and some compilers don't.In this case,not only do we not knowwhether <TT>a[i]</TT> or <TT>a[i+1]</TT> is written to,it ispossiblethat a completely unrelated cell of the array(or any random part of memory)is written to,and it is also not possible to predictwhat final value <TT>i</TT> will receive.See questions <a href="faqcatee08.html?sec=expr#evalorder2">3.2</a>,<a href="faqcatee08.html?sec=expr#ieqiplusplus">3.3</a>,<a href="faqcat7d4b.html?sec=ansi#undef">11.33</a>,and<a href="faqcat7d4b.html?sec=ansi#experiment">11.35</a>.<hr><hr><hr><a name="experiment"><h1>comp.lang.c FAQ list<font color=blue>·</font><a href="../../expr/experiment.html"><!-- qtag -->Question 3.10a</a></h1><p><font face=Helvetica size=8 color=blue><b>Q:</b></font>People keep saying that the behaviorof <TT>i = i++</TT>is undefined,butI just triediton an ANSI-conforming compiler,and got the results I expected.</p><p><hr><p><font face=Helvetica size=8 color=blue><b>A:</b></font>See question <a href="faqcat7d4b.html?sec=ansi#experiment">11.35</a>.<hr><hr><hr><a name="expec0"><h1>comp.lang.c FAQ list<font color=blue>·</font><a href="../../expr/expec0.html"><!-- qtag -->Question 3.10b</a></h1><p><font face=Helvetica size=8 color=blue><b>Q:</b></font>People told me that if I evaluated an undefined expression,or accessed an uninitialized variable,I'd get a random, garbage value.But I tried it, and got <em>zero</em>.What's up with that?</p><p><hr><p><font face=Helvetica size=8 color=blue><b>A:</b></font>It's hard to answer this question,because it's hard to seewhat thecitation ofthe ``unexpected'' value of 0 is supposed to prove.C does guarantee thatcertainvalues will be initialized to 0(see question <a href="faqcatd3c2.html?sec=decl#initval">1.30</a>),but for the rest(and certainly for the results of those undefined expressions),it <em>is</em> true that you might get garbage.The fact that you happened to get 0one timedoes not meanyou were wrong to have expected garbage,nor does it mean that you can depend on this happening next time(much lessthat you shouldwrite code which depends on it!).</p><p>Most memory blocks newly delivered by the operating system,and most as-yet-untouched stack frames,do tend to be zeroed,sothe first time you access them,they may happen to contain 0,but after a program has run for a while,these regularities rapidly disappear.(And programs which unwittingly depend ona circumstantial initial value of an uninitialized variablecan be <em>very</em> difficult to debug,because the ``expected'' values may coincidentally arisein all the small, easy test cases,while the unexpeccted values and the attendant crashes happenonly in the larger, longer-running, much-harder-to-trace-through invocations.)<hr><hr><hr><a name="confused"><h1>comp.lang.c FAQ list<font color=blue>·</font><a href="../../expr/confused.html"><!-- qtag -->Question 3.11</a></h1><p><font face=Helvetica size=8 color=blue><b>Q:</b></font>How can I avoid these undefined evaluation order difficultiesif I don't feel like learning the complicated rules?</p><p><hr><p><font face=Helvetica size=8 color=blue><b>A:</b></font>The easiest answeris that if you steer clear of expressionswhich don't havereasonablyobviousinterpretations,for the most part you'll steer clear ofthe undefined ones,too.(Of course,``reasonably obvious''means different things to different people.This answer works as long as you agreethat<TT>a[i] = i++</TT> and <TT>i = i++</TT>are not ``reasonably obvious.'')</p><p>To be a bit more precise,here are somesimpler rules which,though slightly more conservative thanthe ones in the Standard,willhelp tomake sure that your code is``reasonably obvious''andequally understandable to both the compiler <em>and</em> your fellow programmers:<OL><li>Make sure that eachexpressionmodifies at most one object.By ``object'' we mean eithera simple variable,ora cell of an array,orthelocationpointed to by a pointer (e.g. <TT>*p</TT>).A ``modification'' is eithersimple assignment with the <TT>=</TT> operator,ora compound assignmentwith an operator like <TT>+=</TT>, <TT>-=</TT>, or <TT>*=</TT>,or an increment or decrement with <TT>++</TT> or <TT>--</TT>(in either pre or post forms).<li>If an object(as defined above)appears more than once in an expression,and is the object modified in the expression,make sure that<em>all</em> appearances of the objectwhich fetch its valueparticipate in the computation of the new value which is stored.This rule allows the expression<pre> i = i + 1</pre>because although the object <TT>i</TT> appears twice and is modified,the appearance (on the right-hand side)which fetches <TT>i</TT>'s old valueis used to compute <TT>i</TT>'s new value.<li>If you want to break rule 1,make sure that the several objects being modified are distinctly different,and try to limit yourself to two or at most three modifications,and of a style matching those of the following examples.(Also,make sure that you continue to follow rule 2for each object modified.)The expression<pre> c = *p++</pre>is allowed under this rule,because the two objects modified (<TT>c</TT> and <TT>p</TT>)are distinct.The expression<pre> *p++ = c</pre>is also allowed,because <TT>p</TT> and <TT>*p</TT>(i.e. <TT>p</TT> itself and what it points to)are both modified but are almost certainly distinct.Similarly, both<pre> c = a[i++]and a[i++] = c</pre>are allowed,because <TT>c</TT>, <TT>i</TT>, and <TT>a[i]</TT> arepresumablyall distinct.Finally, expressions like<pre> *p++ = *q++</pre>and<pre> a[i++] = b[j++]</pre>in which <em>three</em> things are modified(<TT>p</TT>, <TT>q</TT>, and <TT>*p</TT> in the first expression,and <TT>i</TT>, <TT>j</TT>, and <TT>a[i]</TT> in the second),are allowed <em>if</em> all three objects are distinct,i.e. only if two <em>different</em> pointers <TT>p</TT> and <TT>q</TT>or two <em>different</em> array indices <TT>i</TT> and <TT>j</TT>are used.<li>You may also break rule 1 or 2as long as you interposea defined sequence point operatorbetween the two modifications,or between the modification and the access.The expression<pre> (c = getchar()) != EOF && c != '\n'</pre>(commonly seen in a <TT>while</TT> loop whilereading a line)is legal becausethe second access of the variable <TT>c</TT>occurs after the sequence point implied by <TT>&&</TT>.(Without the sequence point,the expression would be illegalbecause the access of <TT>c</TT> while comparing it to <TT>'\n'</TT>on the rightdoesnot ``determine the value to be stored''on the left.)<hr><hr><hr><a name="prevspost"><h1>comp.lang.c FAQ list<font color=blue>·</font><a href="../../expr/prevspost.html"><!-- qtag -->Question 3.12a</a></h1><p><font face=Helvetica size=8 color=blue><b>Q:</b></font>What's the difference between <TT>++i</TT> and <TT>i++</TT>?</p><p><hr><p><font face=Helvetica size=8 color=blue><b>A:</b></font>If your C book doesn't explain, get a better one.Briefly:<TT>++i</TT> adds one tothe stored value of<TT>i</TT>and ``returns'' thenew,incremented valueto the surrounding expression;<TT>i++</TT>adds oneto <TT>i</TT> butreturns the prior, unincremented value.<hr><hr><hr><a name="plusplus"><h1>comp.lang.c FAQ list<font color=blue>·</font><a href="../../expr/plusplus.html"><!-- qtag -->Question 3.12b</a></h1><p><font face=Helvetica size=8 color=blue><b>Q:</b></font>If I'm not using the value of the expression,should I use <TT>++i</TT> or <TT>i++</TT> to increment a variable?</p><p><hr><p><font face=Helvetica size=8 color=blue><b>A:</b></font>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++.)Some people will tell you that in the old days one form was preferredover the other because it utilized a PDP-11 autoincrementaddressing mode,but those people are confused.An autoincrement addressing mode can only help if a pointervariable is being incremented and indirected upon,as in<pre> register char c, *cp; c = *cp++;</pre>See also question <a href="faqcatee08.html?sec=expr#ieqiplusplus">3.3</a>.</p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -