-4

So I've been reading a C++14 book (it's the latest my library had), and something has been swimming 'round my head although I'm around 100-200 pages deeper than it, but at some point it mentions this slap in the face:

i++ + ++i;

It says to not do this, but I did it anyway. In both Visual Studio C++ and online C++ compilers (specifically onlinegdb), it gives me 3 when int i = 1;, however when I assign i = i++ + ++i;, online compilers give me 4 and Visual Studio gives me 5... Let's see, if i++ increments i but is the original value, and ++i increments i and is the new and improved i, then if int i = 1; , we'd be doing:

1 + 2;

And i would be 3! Both compilers say this. However i = i++ + ++i; gives different answers! I wish I could verify this, but I can't compute in my head the assignment and the increments. Maybe that's what the compilers are doing as well, one's assigning then incrementing in the expression and the other's doing the opposite. A spirit sort of PEMDAS vs PEDMAS in action.

So I know this is a literal textbook example of undefined behavior, but I'll ask the question anyway: Is there any use of undefined behavior in practice, is there ever a good reason to use this specific piece of code (there probably isn't because of the monstrous nature of it), and is there anything else to note about this code (and its deal)?

dbush
  • 205,898
  • 23
  • 218
  • 273
Epidem7c
  • 877
  • 1
  • 3
  • 7
  • 2
    the reason it exists is basically so different compilers can do it the most efficient way for that compiler, even if that's different for different compilers – user253751 May 05 '23 at 03:01
  • Potential uses of UB would be to maliciously exploit it later; leave some sort of Easter egg; try to force different behaviors for exact same code in different machines – Jardel Lucca May 05 '23 at 03:05
  • The only "good" undefined behavior is for code that is specifically designed to be non-portable. If you don't care about portability then you your UB can become DB, or at least known. There is still UB than can always be UB, like the initial value of a block scope `int`, but things like type punning an `int` and a `float` in a union on a x86 machine is always going to "do the right thing" as it is "optimal" – NathanOliver May 05 '23 at 03:13
  • [What Every C Programmer Should Know About Undefined Behavior](https://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html) – Jason May 05 '23 at 03:33
  • [Why does C++ have 'undefined behaviour' (UB) and other languages like C# or Java don't?](https://softwareengineering.stackexchange.com/questions/398703/why-does-c-have-undefined-behaviour-ub-and-other-languages-like-c-or-java) – Jason May 05 '23 at 03:34
  • @KenWhite You can't write your own [`std::vector` without UB](https://stackoverflow.com/questions/52996590/implementing-a-stdvector-like-container-without-undefined-behavior) and plenty of people have without an issue because every implementation does the sane thing. – NathanOliver May 05 '23 at 03:34
  • @NathanOliver: I've deleted my comment, but the point should be made that if *every implementation does the same thing* would mean that it is no longer UB, because it's the same with every implementation and is being depended on to be so. – Ken White May 05 '23 at 04:37
  • See also [Why are these constructs using pre and post-increment undefined behaviour?](https://stackoverflow.com/q/949433/) – Jonathan Leffler May 05 '23 at 04:48
  • This happens to be by far the #1 FAQ below the C and C++ tags... please do a bit of research before asking and see if this has been asked before. I think this is the 3rd time this week only... – Lundin May 05 '23 at 09:52

1 Answers1

5

In the statement:

i = i++ + ++i;

There are 3 side effects:

  • The assignment to i of the value of the right-hand side of the assignment operator
  • The increment of i as a result of the prefix increment operator
  • The increment of i as a result of the postfix increment operator

In this expression each of these side effects is unsequenced with relation to each other. And the reason we have undefined behavior in this particular case is because i is being modified more than once without an intervening sequence point.

There are a number of different ways in practice that the result could potentially be calculated (i.e. conceivable values include 3, 4, and 5), so there really isn't a good reason to use a piece of code like this.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • 1
    Because the question is also tagged C++: In C++ the side effect of the prefix increment is sequenced before the side effect of the assignment since at least C++11. Since C++17 the side effect of the postfix increment is also sequenced before the assignment's side effect. But the side effects of the pre- and postfix increments remain unsequenced, so it is still UB. – user17732522 May 05 '23 at 05:54