??? 05/28/12 20:51 Read: times Msg Score: +1 +1 Informative |
#187563 - Lazy evaluation demanded Responding to: ???'s previous message |
Justin Fontes said:
Secondly, I believe you are correct about the if statements with your compiler, but there is a slight hiccup. There is no way a break can be used after an if statement. A break only applies to a loop.
The code Erik mentioned is not correct. A loop or a switch statement is needed for break. But correct or not depends on if the posted sample is considered complete code (which it obviously isn't - the variables aren't declared either) or just an example that break can sometimes control program flow in more ways than exiting a multi-iteration loop. And the reason I didn't post assembler instructions for a solution with break, was that for a single standalone if statement, I didn't want to introduce a dummy do { } while (false) just to support "break". But there are situations where I do write such code - it's a kind of poor mans exceptions when writing C code. So a large number of error conditions can jump out of the main execution chain and get handled directly after the while ends - while the "all-is-well" part returns just before the end of the "loop". Another thing is that when writing #define code, it's common to have dummy "do { ... } while (0)" constructs just to make sure that the code looks like a single statement with a demand for a ';' after. So a #define EVAL(x) can (and must) be used as "EVAL(10);" in the source code. And hence guarantee that the code is safe in any combination of if/else. And any smart compiler will recognize that such a loop will always run one (1) time and don't need to result in any real code. It's just syntax glue. However, under the guise that the compiler is not hitting the speed limit of the standard C Optimization ruling and that it is under optimized, the true logic would be to guarantee that all values are tested and that's a strict logic. But the language standard specifically demands early-out for logic expressions. It's not optional. You must be able to test for division-by-zero and perform the division in the same expression without the division-by-zero being computed. And you must be able to use sub-expressions with side effects (like function calls that performs something) without extra function calls being made just for complete evaluation. So it isn't just an issue of speed, but that you in some situations get different results if you do, or do not, compute the complete expression or only as much as is needed to resolve the expression to true or false. An expression with multiple || will (and must) end evaluation on first true. An expression with multiple && will (and must) end evaluation on first false. I am unsure how the C Standard came up with rules to say that certain logic is "the same" and has no impact upon programming because as my analogy showed earlier, fractions with totally different numerators and denominators can have a huge impact on results and cannot be considered to be the same in the case of statistics. So, I guess there are some cases in C, but that seems a little un-trustworthy. The C standard don't care about "the same". The constructs have defined rules for what they must do. And what they must not do. The optimization steps (not demanded by any standard) of better compilers will then look at code and see how the required tasks can be rewritten into lighter sequences of instructions. So a C compiler can always generate different code for "while (true)" and "for (;;)" but there isn't an advantage to do so. They solve the same problem, and if there is an optimum sequence of processor instructions that optimum could be used for both C constructs. In the same way, compilers normally perform much of the for loop evaluations last - but the source construct implies that the break test is done before entering the inner block. So many compilers starts the for loop with a jump to the end of the block, for performing the comparison (but jumping just after the code that performs any post-increment/decrement). In some situations, the compiler can figure out that this jump isn't needed - that the for loop is guaranteed to need at least one iteration, in which case it can perform the body code once before performing the first comparison. So better compilers can skip this jump for a (for i = 0; i < 100; i++) loop. |