C Evaluation
|
07-14-2022, 08:06 PM
(This post was last modified: 07-14-2022 08:13 PM by toml_12953.)
Post: #1
|
|||
|
|||
C Evaluation
What should be printed by the code below? One compiler I used printed
reached f1 reached f2 2 Another printed reached f2 reached f1 2 Which one is right? Here's the code: Code: #include <stdio.h> Tom L Cui bono? |
|||
07-14-2022, 08:34 PM
Post: #2
|
|||
|
|||
RE: C Evaluation
Both are right. C does not specify the order of which the operands of an operator are evaluated. There are exceptions but '*' is not one of them.
Try CC41! |
|||
07-14-2022, 11:44 PM
(This post was last modified: 07-14-2022 11:45 PM by cruff.)
Post: #3
|
|||
|
|||
RE: C Evaluation
To further clarify what Craig B. is saying, the C language specification talks about "sequence points", and permits the compiler to reorder expressions as long as the meaning is not changed. However there is much room for unspecified behavior. If you need to force a specific evaluation order, you must use statements separated by semicolons with intermediate values. You also need to be wary of statements like the following:
Code: i = 0; Where you could possibly get answers of 2 or 3. A good compiler will warn you about this, for example from LLVM clang: Code: % cc -o t t.c Things get even more complex if you are parallel programming and you need to enforce the order of memory accesses as seen by CPUs and DMA devices in a system, but that is a larger subject you probably don't care about at the moment. |
|||
07-15-2022, 01:12 AM
Post: #4
|
|||
|
|||
RE: C Evaluation
Try Compiler Explorer, it support several languages, compilers and targets.
When you are not sure on how the C code get translated into assembly, Compiler Explorer will show you. I am curious, what compilers did you used ? I have tried several C compilers and they all gave me this output: Code: reached f1 I have modified you main function to follow the standard Code: int main(int argc, char* argv[]) { |
|||
07-15-2022, 11:20 PM
Post: #5
|
|||
|
|||
RE: C Evaluation
If you have ever worked with lex and yacc (Yet Another Compiler Compiler) you would understand why evaluation order is not guaranteed. The "natural" way to use yacc puts the operands and operators on a stack and when you "pop" them, they come out in reverse order.
C does have the comma operator which guarantees left to right evaluation, but the commas in function calls are *not* comma operators. If expression does guarantee left to right evaluation and short-circuiting so that you can do something like: if (p && (p->status == 0)) so that p->status is not evaluated if p is NULL. |
|||
07-16-2022, 05:02 PM
(This post was last modified: 07-16-2022 05:02 PM by ijabbott.)
Post: #6
|
|||
|
|||
RE: C Evaluation
(07-15-2022 11:20 PM)KeithB Wrote: If expression does guarantee left to right evaluation and short-circuiting so that you can do something like: It's the && and || operators that guarantee left to right evaluation and short-circuiting. The `if` only cares whether the expression compares equal to 0 or not. — Ian Abbott |
|||
07-16-2022, 06:43 PM
Post: #7
|
|||
|
|||
RE: C Evaluation
(07-15-2022 11:20 PM)KeithB Wrote: If you have ever worked with lex and yacc (Yet Another Compiler Compiler) you would understand why evaluation order is not guaranteed. The "natural" way to use yacc puts the operands and operators on a stack and when you "pop" them, they come out in reverse order. To nit a bit: Runtime evaluation order in C does not depend on a compiler's "front end" (parsing and semantic analysts). LALR (lookahead LR) parsers Yacc and Bison parse C source code left to right (from source code begin to end, hence LR parsing) and build the parse tree bottom-up towards the root, thereby performing a "right most derivation" (hence LR) to produce intermediate (IR) code. The compiler's "back end" then optimizes and translates the IR to the target representation (assembly, machine code, byte code, stack machine, ...). Because C allows aggressive optimization of the IR and the target representation, operands to operators and arguments passed to functions may be evaluated in an unspecified order to facilitate those optimizations, unlike in Java for example. Consider f(++k)+a[k] which exhibits undefined behavior in C. This is on purpose, because we may want to pre-fetch a[k] before the function call f(++k) to hide the latency of the memory fetch that can take many cycles to complete, even with fast L1/L2 caches. Once f(++k) is done, a[k] is ready to be consumed by the CPU so to speak. Of course, it is still possible to call f(k+1) instead of f(++k) to preserve k in a[k] and then we can increment ++k, but that's not the point. Early compilers were just much simpler and didn't have to bother with that. Without going into too much detail, there is another reason why C (and other PL) typically evaluate function arguments in reverse order (but not always as we know!), which has to do with the way subroutine frames are populated in the generated target code. - Rob "I count on old friends to remain rational" |
|||
« Next Oldest | Next Newest »
|
User(s) browsing this thread: 3 Guest(s)