drb@eecg.toronto.edu (David R. Blythe) (04/08/91)
I recently dug up a copy of the hoc calculator described in kernighan & pike only to discover that the C compiler does not increment pc until after the function call returns in the following statment: (*(*pc++))(); whereas the rest of the program is assuming it is done before the function is actually called. Is the compiler interpretation supposed to be implementation dependent? I would suspect not, but then I can't believe no one else has run into this before (On the other hand K&P is pre-ANSI). Sorry, if this has been hashed out before. And for those keeping score this is IRIX 3.3.1 david blythe ontario centre for large scale computation drb@clsc.utoronto.ca
sweetmr@SCT60A.SUNYCT.EDU (michael sweet) (04/09/91)
> only to discover that the C compiler does not increment pc until after the > function call returns in the following statement: > (*(*pc++))(); The time of increment/decrement IS compiler dependent. The only constraint with ++/-- is that '++i' increments 'i' before using that value, and 'i--' after the valuye is used. This causes MUCH heartache in the above code and the following (which I see all too often, and should NEVER be used if you want to port code to a different machine!) while (*s) *s = *++s; (or similar...) What the person probably wants to do is delete a character from a string (starting at 's'...). The idiot assumes that '*s' is evaluated for the assignment FIRST, and then 's' is incremented. A nicer way (which will get optimized away anyway) and MORE READABLE way is: while (*s) { *s = *(s+1); s++; }; The KISS philosophy is best when coding in C (keeps you from going crazy!) -Mike Sweet ------------------------------------------------------------------------------ "The only TASC (315) 724-1100 (voice) truth is that 555 French Road (315) 724-2031 (fax) there are no New Hartford, NY 13413 Internet: sweetmr@sct60a.sunyct.edu truths, only beliefs." Delphi: DODGECOLT ------------------------------------------------------------------------------
sysmark@aurora.physics.utoronto.ca (Mark Bartelt) (04/13/91)
David Blythe wrote ... | I recently dug up a copy of the hoc calculator described in kernighan & pike | only to discover that the C compiler does not increment pc until after the | function call returns in the following statment: | (*(*pc++))(); | whereas the rest of the program is assuming it is done before the function is | actually called. Is the compiler interpretation supposed to be implementation | dependent? I would suspect not, but then I can't believe no one else has ... to which Michael Sweet replied ... | The time of increment/decrement IS compiler dependent. The only constraint | with ++/-- is that '++i' increments 'i' before using that value, and 'i--' | after the valuye is used. This causes MUCH heartache in the above code and | the following (which I see all too often, and should NEVER be used if you want | to port code to a different machine!) | | while (*s) | *s = *++s; Sorry, but this example is irrelevant to the bug being reported (and it is a bug, if the behaviour of the SGI compiler is in fact what David reports it to be; I haven't yet confirmed that it is, though I have no reason to doubt that it is). It's certainly true that the *s = *++s stuff is a proper example of bad code, since C "does not specify the order in which the operands of an operator are evaluated" [K&R-2, 2.12]. However, this has no bearing on David's question. The critical issue here is what happens during expression evaluation. Since the incrementing of an operand (after noting its value) is part of the definition of the semantics of the postfix ++ operator, it seems quite clear that postfix incrementing has to be treated as an atomic operation. In other words, the operand gets incremented after its value is noted, but before anything else happens. K&R is admittedly a bit vague about this ("After the value is noted, the operand is incremented ..." [A7.3.4]), but I think it's universally acknowledged that "after" means "immediately after". I'm sure that some high-level guru will correct me if I'm wrong, but I don't think I am. As a further confirmation that the delay (until after the return from the function call) in the postincrement of pc is truly a bug, doesn't the fact that David's example was taken from Kernighan and Pike, coupled with the fact that bwk is the 'K' in "K&R", suggest something? Mark Bartelt 416/978-5619 Canadian Institute for mark@cita.toronto.edu Theoretical Astrophysics mark@cita.utoronto.ca
davea@quasar.wpd.sgi.com (David B.Anderson) (04/13/91)
In article <1991Apr12.175909.5194@helios.physics.utoronto.ca> mark@cita.toronto.edu writes: >David Blythe wrote ... > >| I recently dug up a copy of the hoc calculator described in kernighan & pike >| only to discover that the C compiler does not increment pc until after the >| function call returns in the following statment: >| (*(*pc++))(); >| whereas the rest of the program is assuming it is done before the function is >| actually called. Is the compiler interpretation supposed to be implementation >| dependent? I would suspect not, but then I can't believe no one else has [ ] >Sorry, but this example is irrelevant to the bug being reported (and it is a >bug, if the behaviour of the SGI compiler is in fact what David reports it to Since Mark Bartelt claims that the compiler is wrong, I'll step up to its defense (I do not claim that the compiler version used is ANSI C): ANSI C: 3.3.2.2, page 42. line 20. ``The order of evaluation of the function designator, the arguments, and subexpressions within the arguments is unspecified, but there is a sequence point before the actual call.'' The Standard does not say whether the sequence point is before or after the evaluation of the function designator. The following is thus _a_ legal sequence: evaluate arguments (none in the case above) sequence point (arguments evalation complete) evaluate function designator call function increment pc statement sequence point So IMO our code generation is legal in this case. (case dismissed :-) Regards, [ David B. Anderson Silicon Graphics (415)335-1548 davea@sgi.com ] [``What can go wrong?'' --Calvin to Hobbes]
sysmark@aurora.physics.utoronto.ca (Mark Bartelt) (04/13/91)
In article <97139@sgi.sgi.com> davea@quasar.UUCP (David B.Anderson) writes: | Since Mark Bartelt claims that the compiler is wrong, I'll step up to its | defense (I do not claim that the compiler version used is ANSI C): | | ANSI C: 3.3.2.2, page 42. line 20. | ``The order of evaluation of the function designator, the arguments, | and subexpressions within the arguments is unspecified, but there is | a sequence point before the actual call.'' | | The Standard does not say whether the sequence point is before or | after the evaluation of the function designator. | | The following is thus _a_ legal sequence: | evaluate arguments (none in the case above) | sequence point (arguments evalation complete) | evaluate function designator | call function | increment pc | statement sequence point | | So IMO our code generation is legal in this case. (case dismissed :-) Hmm... Interesting interpretation. But ... I *think* (and though I feel reasonably proficient in C, I nonetheless lay no claim to being in a class with, say, Henry Spencer, let alone dmr or bwk) that in this case the | evaluate function designator *includes* the incrementing of pc. Observe that the sequence note the value of the operand increment the operand is, in its entirety, part of the semantics of the postfix ++ operator. At least, that's *my* interpretation of what the standard says. Maybe we should cross-post this to comp.lang.c (which would generate all sorts of comments, most of them bogus), or forward the discussion to dmr and bwk, and see whether either of them care to provide a definitive answer. Mark Bartelt 416/978-5619 Canadian Institute for mark@cita.toronto.edu Theoretical Astrophysics mark@cita.utoronto.ca
vd09+@andrew.cmu.edu (Vincent M. Del Vecchio) (04/14/91)
I'm not sure I understand what the discussion is about here, though I'd like to. Is the complaint that pc gets incremented after the function returns, instead of immediately before? In other words, the correct function gets called, but pc has a "wrong" value during the execution of the function? Or is it something else? -Vincent Del Vecchio vd09@andrew.cmu.edu
jit@SLIC.CELLBIO.DUKE.EDU (Jit Keong Tan) (04/14/91)
Let me join the crowd. In article <1991Apr12.175909.5194@helios.physics.utoronto.ca> mark@cita.toronto.edu writes: >David Blythe wrote ... > > I recently dug up a copy of the hoc calculator described in kernighan & pike > only to discover that the C compiler does not increment pc until after the > function call returns in the following statment: > (*(*pc++))(); > whereas the rest of the program is assuming it is done before the function is > actually called. Is the compiler interpretation supposed to be implementation > dependent? I would suspect not, but then I can't believe no one else has CASE 1 ====== My interpretation of (*(*pc++))() is 1) Parse the innermost parenthesis: i) location A = *pc ii) pc++ 2) *(location A) is a function pointer, call the function. So pc should increment BEFORE the function is called. CASE 2 ====== If it is (**pc++)(), it should be fairly straight forward. 1) location A = *pc 2) *(location A) is a function pointer, call the function 3) pc++ So the increment should be AFTER the function is called. =========================================== I wrote a little program to support my argument but of all 3 compilers that I tested (SGI, GNU, SUN) did not fully support me. So I may be wrong. But I still like to think that I have interpreted it correctly. Here's my little program: ---------------------------------------------------------------------- /* JKT test of compiler behavior on function pointer */ /* Any comment is very much welcome. jit@slic.cellbio.duke.edu */ #include <stdio.h> void (**ptr)(); void (*fptr[3])(); void pr_all_ptr(); void fa(); void fb(); void fc(); main() { fptr[0] = fa; fptr[1] = fb; fptr[2] = fc; ptr = fptr; printf("==============Before any changes\n"); pr_all_ptr(); printf("==============( **ptr++) ()\n"); ptr = fptr; (**ptr++) (); printf("After ==( **ptr++) ()\n"); pr_all_ptr(); printf("==============( * (*ptr++)) ()\n"); ptr = fptr; (* (*ptr++)) (); printf("After ==( * (*ptr++)) ()\n"); pr_all_ptr(); } void pr_all_ptr() { printf("f?(): fa(%X h) fb(%X h) fc(%X h)\n", (int)fa, (int)fb, (int)fc); printf("fptr: [0](%X h) [1](%X h) [2](%X h)\n", (int)fptr[0], (int)fptr[1], (int)fptr[2]); printf("**ptr: %X h\n",(int)**ptr); } void fa() { static int count=0; printf("fa being called %d\n",count++); pr_all_ptr(); printf("Before Exiting fafafafafafa\n"); } void fb() { static int count=0; printf("fb being called %d\n",count); pr_all_ptr(); printf("Before Exiting fbfbfbfbfbfbfb\n"); } void fc() { static int count=0; printf("fc being called %d\n",count); pr_all_ptr(); printf("Before Exiting fcfcfcfcfcfcfc\n"); } END OF PROGRAM ---------------------------------------------------------------------- The following is the output of the sample program from SGI, GNU, SUN: SGI ==============Before any changes f?(): fa(40036C h) fb(4003B4 h) fc(4003F0 h) fptr: [0](40036C h) [1](4003B4 h) [2](4003F0 h) **ptr: 40036C h ==============( **ptr++) () fa being called 0 f?(): fa(40036C h) fb(4003B4 h) fc(4003F0 h) fptr: [0](40036C h) [1](4003B4 h) [2](4003F0 h) **ptr: 40036C h Before Exiting fafafafafafa After ==( **ptr++) () f?(): fa(40036C h) fb(4003B4 h) fc(4003F0 h) fptr: [0](40036C h) [1](4003B4 h) [2](4003F0 h) **ptr: 4003B4 h ==============( * (*ptr++)) () fa being called 1 f?(): fa(40036C h) fb(4003B4 h) fc(4003F0 h) fptr: [0](40036C h) [1](4003B4 h) [2](4003F0 h) **ptr: 40036C h Before Exiting fafafafafafa After ==( * (*ptr++)) () f?(): fa(40036C h) fb(4003B4 h) fc(4003F0 h) fptr: [0](40036C h) [1](4003B4 h) [2](4003F0 h) **ptr: 4003B4 h GNU ==============Before any changes f?(): fa(4003F0 h) fb(400458 h) fc(4004B0 h) fptr: [0](4003F0 h) [1](400458 h) [2](4004B0 h) **ptr: 4003F0 h ==============( **ptr++) () fa being called 0 f?(): fa(4003F0 h) fb(400458 h) fc(4004B0 h) fptr: [0](4003F0 h) [1](400458 h) [2](4004B0 h) **ptr: 400458 h Before Exiting fafafafafafa After ==( **ptr++) () f?(): fa(4003F0 h) fb(400458 h) fc(4004B0 h) fptr: [0](4003F0 h) [1](400458 h) [2](4004B0 h) **ptr: 400458 h ==============( * (*ptr++)) () fa being called 1 f?(): fa(4003F0 h) fb(400458 h) fc(4004B0 h) fptr: [0](4003F0 h) [1](400458 h) [2](4004B0 h) **ptr: 400458 h Before Exiting fafafafafafa After ==( * (*ptr++)) () f?(): fa(4003F0 h) fb(400458 h) fc(4004B0 h) fptr: [0](4003F0 h) [1](400458 h) [2](4004B0 h) **ptr: 400458 h SUN ==============Before any changes f?(): fa(2434 h) fb(2488 h) fc(24CC h) fptr: [0](2434 h) [1](2488 h) [2](24CC h) **ptr: 2434 h ==============( **ptr++) () fa being called 0 f?(): fa(2434 h) fb(2488 h) fc(24CC h) fptr: [0](2434 h) [1](2488 h) [2](24CC h) **ptr: 2488 h Before Exiting fafafafafafa After ==( **ptr++) () f?(): fa(2434 h) fb(2488 h) fc(24CC h) fptr: [0](2434 h) [1](2488 h) [2](24CC h) **ptr: 2488 h ==============( * (*ptr++)) () fa being called 1 f?(): fa(2434 h) fb(2488 h) fc(24CC h) fptr: [0](2434 h) [1](2488 h) [2](24CC h) **ptr: 2488 h Before Exiting fafafafafafa After ==( * (*ptr++)) () f?(): fa(2434 h) fb(2488 h) fc(24CC h) fptr: [0](2434 h) [1](2488 h) [2](24CC h) **ptr: 2488 h -------------------------------------------------------- Jit Keong Tan | internet: jit@slic.cellbio.duke.edu (919) 684-8098 | bitnet : tan00001@dukemc.bitnet -------------------------------------------------------- U.S. Mail: Duke University Medical Center Department Of Cell Biology Box 3709 Nanaline Duke Bldg, Rm. 349 Durham, NC 27710
davea@quasar.wpd.sgi.com (David B.Anderson) (04/16/91)
David Blythe wrote: > I recently dug up a copy of the hoc calculator described in kernighan & pike > only to discover that the C compiler does not increment pc until after the > function call returns in the following statment: > (*(*pc++))(); Recently, I quoted ANSI C: 3.3.2.2, page 42. line 20. ``The order of evaluation of the function designator, the arguments, and subexpressions within the arguments is unspecified, but there is a sequence point before the actual call.'' as justifying the Release 3.3.x C compiler in compiling the above statement. I was wrong and the 3.3 C compiler is wrong. The variable ``pc'' must be incremented after the function address is calculated but *before* the function is called. There is no ambiguity in the Standard, but I somehow misunderstood the quoted sentence in the Standard. I would like to thank Mark Bartelt (mark@cita.toronto.edu) for being persistent (via e-mail) and helping me to understand my error. The C compiler bug is fixed in the next release of IRIX (4.0). My apologies to anyone mislead by my error. Regards, [ David B. Anderson Silicon Graphics (415)335-1548 davea@sgi.com ] [``What can go wrong?'' --Calvin to Hobbes]
sysmark@aurora.physics.utoronto.ca (Mark Bartelt) (04/17/91)
In article <97603@sgi.sgi.com> davea@quasar.wpd.sgi.com (David B.Anderson) writes: [ regarding David Blythe's question about the compiler's misbehaviour when dealing with (*(*pc++))() ] | I would like to thank Mark Bartelt (mark@cita.toronto.edu) for being | persistent (via e-mail) and helping me to understand my error. Thanks for the thanks, but most of the credit really should go to Henry Spencer (UofT's local source of ultimate oracular wisdom on anything and everything related to C, UNIX, and a host of other things), who offered his interpretation of what the standard says. For those of you who may be interested, here are his comments: | ANSI C's sequence-point stuff is, in general, enough to make your head | ache. However, in this case the standard is clear [ ... ] | | 3.3.2.2: "The order of evaluation of the function designator, | the arguments, and the subexpressions within the arguments is unspecified, | but there is a sequence point before the actual call." | | This very issue -- increments vs. function calls -- was a hotly-debated | point both before and during standardization, hence the very explicit | resolution of it. Consulting Henry also afforded an opportunity to get my own (incorrect) opinions on a couple of matters straightened out. Specifically: (1) In one of my previous postings, I offered biblical quotes (K&R-2) to support my contention that the compiler was misbehaving. Dave Anderson pointed out that doing so was wrong (albeit a common mistake), and that the standard is now the only proper arbiter of correct behaviour. Henry backed this up, saying: | your correspondent is correct in saying that nothing short of the | actual standard is authoritative on the fine points. K&R2 not only made no | attempt to be authoritative, but is wrong in small things due to having | been written based on a late draft rather than the final standard. (2) At one point, I asserted that Since the incrementing of an operand (after noting its value) is part of the definition of the semantics of the postfix ++ operator, it seems quite clear that postfix incrementing has to be treated as an atomic operation. Wrongo. Henry offers a correction: | There has never been any promise that postfix ++ was atomic, and indeed | some compilers do postpone the increment a little in some circumstances. Oh, well, it just goes to prove that no matter how cocky and self-confident I seem to be, there'll always be an opportunity to embarrass myself in public with a mistake or two, even when I'm right! :-) Mark Bartelt 416/978-5619 Canadian Institute for mark@cita.toronto.edu Theoretical Astrophysics mark@cita.utoronto.ca