4

Compiler optimization can sometimes skip evaluation of certain statements which have no consequence. However, does this apply to the comma operator too?

The following code runs without any error on ideone, but I expected it to crash.

#include <iostream>

int main() {
    int x = (1/0, 2);
    std::cout << x << std::endl;
}

The program does crash if I change the statement to int x = 1/0;

miken32
  • 42,008
  • 16
  • 111
  • 154
Masked Man
  • 1
  • 7
  • 40
  • 80
  • 5
    _Undefined_ behaviour is not the same as a guaranteed crash. – jogojapan Feb 21 '13 at 06:29
  • Fair enough, but what if the left operand is not UB? Can the compiler skip it? – Masked Man Feb 21 '13 at 06:46
  • I believe it's as Alok explains in the answer, i.e. it depends on whether anything observable happens. And this is true [not only for the comma operator](http://stackoverflow.com/questions/3863656/how-to-cause-an-intentional-division-by-zero). (Btw, despite my comment, I think this is a good question, I +1ed both question and answer.) – jogojapan Feb 21 '13 at 06:48

1 Answers1

8

Compiler optimizations use the As-if rule.

The as-if rule

Allows any and all code transformations that do not change the observable behavior of the program

So Yes, the compiler can optimize this. Check the following modified sample:

#include <iostream>

int main() 
{
    int y = 1;
    int x = (y=1/0, 2);
    std::cout << x << std::endl;
    //std::cout << y << std::endl;
} 

Commenting the last line compiles and executes this code correctly while uncommenting it gives you the expected undefined behavior.

As @jogojapan correctly points out,
It is important to note that compiler optimizations are not guaranteed by the standard and divide by zero is a Undefined behavior. So this code does have an undefined behavior. Whether the observable behavior is because of compiler optimizing out the divide by zero or due to undefined behavior we can never know. Technically, it is Undefined behavior all the same.

Community
  • 1
  • 1
Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • 2
    I don't think that is so easy. What is "*observable behavior*"? If it evaluates `1/0`, then you would "observe" a **different** behavior. Means, the behavior of the program is different based on the optimization decision. – Nawaz Feb 21 '13 at 06:16
  • @Nawaz: In this case the compiler can accurately detect that the result of evaluation of sub-expression of comma operator is never used and hence it can simply optimize it out. If this result is used the compiler cannot and will not apply the optimization. – Alok Save Feb 21 '13 at 06:18
  • You mean, the same program would run differently for different optimization mode (and for different compilers)? I don't think that would be correct then. – Nawaz Feb 21 '13 at 06:20
  • 3
    @AlokSave: it's not that the sub expression is never used, it also must consider side-effects of expressions. And this clearly has an observable side-effect. I can only assume that division by zero is undefined behavior, so the compiler can _assume_ (incorrectly in this case) that there is no effective side effect, and _then_ the as-if rule can apply. (assignment to a local variable does not count as a side-effect.) – Mooing Duck Feb 21 '13 at 06:22
  • 3
    It's kind of futile to discuss whether undefined behaviour is observable... Btw a similar problem has been discussed here before: http://stackoverflow.com/questions/3863656/how-to-cause-an-intentional-division-by-zero – jogojapan Feb 21 '13 at 06:26
  • @AlokSave sure. commented, the compiler observed the division and result were completely unrelated to any side efects of the program, so it diacarded them. In the second example, the statement is required for a later side efffect, so it must be executed. If you have `int main(){ int a=1/0;}` and run it optimized, you probably wont get an error there either: http://ideone.com/mgsQVT Has nothing at all to do with the comma. – Mooing Duck Feb 21 '13 at 06:34
  • 2
    @Nawaz: The key thing here is that compilator must preserve all **defined** behaviour. Behaviour of `1/0` is (explicitly) **undefined** and therefore the compiler may or may not trigger the exception. – Jan Hudec Feb 21 '13 at 06:36
  • @Nawaz: Perhaps you are correct or maybe not. As jogojapan, points out technically this is indeed undefined behavior whether or not the compiler chooses to optimize it or not is impossible to say. – Alok Save Feb 21 '13 at 06:36
  • 3
    @MooingDuck: `int main(){ int a=1/0;}` is still Undefined behavior. So whether or not a compiler can or may optimize it is okay for the case of discussion but the discussion itself doesn't hold good because technically it is UB all the same. – Alok Save Feb 21 '13 at 06:38
  • @JanHudec: I think we agree? or you misunderstood my point? The expression `(1/0, 2)` *semantically* invokes undefined behavior, irrespective of whether the compiler *actually* evaluates the first sub-expression or not. If it evaluates, GCC produces code which crashes at runtime *which* is observable. – Nawaz Feb 21 '13 at 06:50