geoff@locus.com (Geoff Kuenning) (02/05/91)
The following little program demonstrates a problem found in the XSend() routine of XlibInt.c: main () { int i = 0; while (i < 3) { int j = 4; printf ("i = %d, j = %d\n", i, j); i++; j++; } } What does this print? On the machine I'm using, it prints the same value for j (j = 4) three times. On the other hand, the programmer of XSend() clearly expected three different values for j. I just checked the ANSI C spec on this, and found it unclear. It is explicitly stated that automatics are initialized on every entry to a compound statement. However, it is not made clear whether the construct: while (<expression>) <statement> is considered to *re-enter* the compound statement every time or not. My instinct says yes, the statement is re-entered, but obviously this interpretation is open to discussion. In terms of usefulness, I could argue that either option is useful to programmers. What do people think the spec should do about this question? (BTW, the spec explicitly says that implementations get to decide whether automatics are initialized upon jumps into a compound statement, so perhaps this issue should also be implementation-defined). I'm cross-posting to comp.windows.x so that X-Windows users will be made aware of a potential bug (the problem will show up only under certain very rare conditions, so it could be lurking in your system without your knowledge). -- Geoff Kuenning geoff@la.locus.com geoff@ITcorp.com
bhoughto@hopi.intel.com (Blair P. Houghton) (02/06/91)
In article <1991Feb5.023809.389086@locus.com> geoff@locus.com (Geoff Kuenning) writes: >The following little program demonstrates a problem found in the XSend() >routine of XlibInt.c: > > main () > { > int i = 0; > while (i < 3) > { > int j = 4; > printf ("i = %d, j = %d\n", i, j); > i++; > j++; > } > } Digression: does anyone know where this style (having the statements aligned with the braces that enclose them) came from? Before a few months ago I'd never seen it, and now I've seen it in a dozen programs. Who's fomenting this bletcherous bowdlerization of my beloved C? >I just checked the ANSI C spec on this, and found it unclear. It is >explicitly stated that automatics are initialized on every entry to a >compound statement. However, it is not made clear whether the construct: > > while (<expression>) > <statement> > >is considered to *re-enter* the compound statement every time or not. My >instinct says yes, the statement is re-entered, but obviously this >interpretation is open to discussion. In terms of usefulness, I could >argue that either option is useful to programmers. You answer your own question by your example. A statement is a statement is a statement, and the `while' has no clue whether the statement is compound or simple; it merely transfers control to it when the conditional-expression evaluates nonzero, and takes back control when its end is reached. Any auto variables within the compound statement can be reallocated as the implementation desires, and must be reinitialized. In the description of the compound statement: "The initializers of objects that have automatic storage duration are evaluated and the values are stored in the objects..." (ANSI X3.159-1989, sec. 3.6.2, p. 77, ll. 4-5) >What do people think the spec should do about this question? At most, add the definition of the term "entry" to section 1.6, Definition of Terms; although that'd be a bit of overkill. It might even be too much to ask for a footnote where that use of the word appears (see below). >(BTW, the >spec explicitly says that implementations get to decide whether automatics >are initialized upon jumps into a compound statement, No it doesn't. In sec. 3.1.2.4, Storage Duration of Objects, it explains automatic storage, guarantees that the object will exist whether you get into the statement through "...normal entry to the block with which it is associated, or on a jump from outside the block to a labeled statement in the block..." (Ibid, sec. 3.1.2.4, p. 23, l. 14), then says: "If an initialization is specified for the value stored in the object, it is performed on each normal entry, but not if the block is entered by a jump to a labeled statement" (Ibid, ll. 16-18). Ergo, jump to a labeled statement, and the initialization is skipped. (Without a labeled statement, you can't get there from here). Note that in: /* just a block to scope-limit foo and bar */ { int foo = 3; mickle: int bar = 0111; foo *= bar; } `mickle:' labels `foo *= bar;', which is a statement, rather than `int bar = 0111;', which is a declaration, not a statement. So, despite the fact that `int bar = 0111;' appears after `mickle:', it is guaranteed that neither initialization is performed. >I'm cross-posting to comp.windows.x so that X-Windows users will be made >aware of a potential bug (the problem will show up only under certain >very rare conditions, so it could be lurking in your system without your >knowledge). It (the character of the bug, not this particular bug) does explain a few things I noticed about some commercial implementations of the X-servers (from a company who shall remain nameless), most notably the every-other-X-server bugs, where you'd get odd alterations to X defaults on every other time you reran the server (it dies and restarts with every console-window logout). The most common one was that the screen-blanking would be reset to 0 seconds. Very annoying. There were others involving massive destruction of the X error logging file when one tried to get fonts using certain _legal_ font-naming patterns. It left many megabytes of nulls in the error log, clogging the root partition. Then it dumped 2mb of X-server core in there, too, which stuck despite the clog... --Blair "Although their initials are DEC."
gwyn@smoke.brl.mil (Doug Gwyn) (02/06/91)
In article <1991Feb5.023809.389086@locus.com> geoff@locus.com (Geoff Kuenning) writes:
- while (i < 3)
- {
- int j = 4;
- printf ("i = %d, j = %d\n", i, j);
- i++;
- j++;
- }
-What does this print? On the machine I'm using, it prints the same value
-for j (j = 4) three times. On the other hand, the programmer of XSend()
-clearly expected three different values for j.
The programmer clearly made a mistake. j has the value 4 for each
execution of the printf(). I was unable to tell from the code
snippet just what the programmer intended; merely changing the
storage class of j to "static" would probably not be correct either.
-I just checked the ANSI C spec on this, and found it unclear. It is
-explicitly stated that automatics are initialized on every entry to a
-compound statement. However, it is not made clear whether the construct:
- while (<expression>)
- <statement>
-is considered to *re-enter* the compound statement every time or not.
There is no question whatsoever about this. The compound statement is
completely evaluated for each iteration; this includes the auto
initialization.
blodgett@apollo.HP.COM (Bruce Blodgett) (02/06/91)
In article <2293@inews.intel.com> bhoughto@hopi.intel.com (Blair P. Houghton) writes: > Note that in: > > /* just a block to scope-limit foo and bar */ > { > int foo = 3; > mickle: > int bar = 0111; > > foo *= bar; > } > > `mickle:' labels `foo *= bar;', which is a statement, > rather than `int bar = 0111;', which is a declaration, not > a statement. So, despite the fact that `int bar = 0111;' > appears after `mickle:', it is guaranteed that neither > initialization is performed. Section 3.6.1 (Labeled Statements) provides relevant syntax: labeled-statement: identifier : statement As does Section 3.6.2 (Compound Statement, or Block): compound-statement: { opt-declaration-list opt-statement-list } Your declarations of foo and bar make up the optional declaration-list. foo *= bar; makes up the optional statement-list. The label mickle: precedes a declaration, not a statement. This is not syntactically legal. There is not a question of whether to assign 0111 to bar "if the block is entered by a jump to a labeled statement", because you have not provided a legal code fragment. Bruce Blodgett blodgett@apollo.hp.com (508) 256-0176 x4037
rns@tortuga.SanDiego.NCR.COM (Rick Schubert) (02/07/91)
In article <2293@inews.intel.com> bhoughto@hopi.intel.com (Blair P. Houghton) writes: >In article <1991Feb5.023809.389086@locus.com> geoff@locus.com (Geoff Kuenning) writes: >>(BTW, the >>spec explicitly says that implementations get to decide whether automatics >>are initialized upon jumps into a compound statement, >No it doesn't. >Ergo, jump to a labeled statement, and the initialization is skipped. >Note that in: > /* just a block to scope-limit foo and bar */ > { > int foo = 3; >mickle: > int bar = 0111; > > foo *= bar; > } > it is guaranteed that neither >initialization is performed. Someone else answered that the label is invalid here, so I'll proceed as if the label were after the declarations. In this case it CANNOT be guaranteed that the initialization is NOT performed since there is no way to tell (in a Standard Conforming program) that the initialization was or was not done. There is no way to test for an uninitialized value. The only thing that would be invalid for the implementation (compiler) to do would be to evaluate an initialization expression that had side-effects that could be tested for. -- Rick Schubert (rns@tortuga.SanDiego.NCR.COM)
bhoughto@hopi.intel.com (Blair P. Houghton) (02/08/91)
In article <4fa77adf.20b6d@apollo.HP.COM> blodgett@apollo.HP.COM (Bruce Blodgett) writes: >In article <2293@inews.intel.com> bhoughto@hopi.intel.com (Blair P. Houghton) writes: >> mickle: >> int bar = 0111; >> foo *= bar; >> `mickle:' labels `foo *= bar;', which is a statement, [...incrimination deleted...] >The label mickle: precedes a declaration, not a statement. This is >not syntactically legal. Oops. Good thing I don't code that way... --Blair "Stop laughing, Doug."
tom@flood.com (Tom Chatt) (02/12/91)
In article <1991Feb5.023809.389086@locus.com> geoff@locus.com (Geoff Kuenning) writes (paraphrases in brackets): > [ In the following example (drawn from actual Xlib code): ] > > main () > { > int i = 0; > while (i < 3) > { > int j = 4; > printf ("i = %d, j = %d\n", i, j); > i++; > j++; > } > } > > [ Does the initialization of j=4 occur at the start of each iteration > of the compound statement, or only the first iteration? Mr. Kuenning's > compiler sets j=4 each time; the X programmer evidently expected otherwise. > The ANSI C standard says that automatics are initialized on every entry > to a compound statement, but does the above example count as three > entries to the compound statement, or only one? ] WRT entering the compound statement, it seems pretty clear to me that the compound statement is re-entered at each iteration, and that the initialization (as per spec) should occur each time. I say this because the test "i < 3" is clearly outside of the compound statement, and this executes at each iteration, thus you must have exited the compound statement. Though a compiler *may* optimize this out, it would be perfectly correct for a compiler to *allocate* the automatic variable at each entry to the compound statement. In the example above, the programmer has some expectation about the value of the automatic variable persisting outside of its scope (i.e., between iterations). This practice is extremely dubious and inadvisable. If a programmer expects a variable's value to persist outside of its scope, he should declare it as static. -- Tom Chatt \ Don't take offense, take action. Internet: tom@flood.com \ Speak up. When we remain silent, UUCP: ...!uunet!flood!tom / \ we oppress ourselves.