5

I've been looking around and found formula: a = (a + b) - (b = a) it is supposed to swap two variables (or objects in some cases). However I tested it with C++ and php, these gave me different result.

php:

$a = 10;
$b = 20;
$a = ($a + $b) - ($b = $a);
echo $a, " ", $b;

This prints 20 10

C++

int a = 10;
int b = 20;
a = (a + b) - (b = a);
std::cout << a << " " << b;

This prints 10 10

Code looks the same but outputs are different, I've been thinking about two reasons:

  1. C++ code is compiling and php is interpreting.
  2. This formula is useless because it leads to undefined behavior.

Can somebody explains, why C++ and php output differs in this situation?

ST3
  • 8,826
  • 3
  • 68
  • 92
  • 5
    http://stackoverflow.com/questions/949433/could-anyone-explain-these-undefined-behaviors-i-i-i-i-i-etc - your C++ code has undefined behavior. – Mat Aug 04 '13 at 07:58
  • 2
    Are you sure? I copy/pasted your code in my compiler (g++) and I get "20 10" rather than "10 10". – leonm Aug 04 '13 at 08:04
  • 2
    @leonm Which is not surprising if the behavior is undefined. – JJJ Aug 04 '13 at 08:05
  • @leonm I used VS2008 and it gave `10 10`. So as it probably is UB different compilers may process code in different ways, so it just confirms of it beeing UB. – ST3 Aug 04 '13 at 08:05
  • It depends you can get `20 10` but the user is getting `20 10` the behavior is undefined. – Uchia Itachi Aug 04 '13 at 08:06
  • 1
    I also tried here http://www.compileonline.com/compile_cpp_online.php the result was `20 10` –  Aug 04 '13 at 08:06
  • See http://ideone.com/KqluGF -- the output is `20 10` – Amal Murali Aug 04 '13 at 08:10
  • why is this `undefined behavior` is clearly operator precedence? – DevZer0 Aug 04 '13 at 08:29
  • @DevZer0 `a + b` and `b = a` are "isolated" so as Mats says in his answer, "the compiler is allowed to calculate `b = a` before or after it does `a + b` [a]s long as it does `a + b` and `b = a` before the subtraction." – JJJ Aug 04 '13 at 08:41
  • @Juhana oh i see but in php `=` takes higher precedence than `+` – DevZer0 Aug 04 '13 at 10:17
  • @DevZer0 As I said, it doesn't matter because `(a + b)` and `(b = a)` are considered separate expressions. – JJJ Aug 04 '13 at 10:19
  • @Juhana then right to left vs left to right precedence takes over isn't it, so is the argument in C there is no such definition of right to left vs left to right for isolated expression? – DevZer0 Aug 04 '13 at 10:32
  • @DevZer0 No. Read Mats's answer carefully. – JJJ Aug 04 '13 at 10:35
  • The simplest answer to the question "why am I seeing different behavior in C++ and PHP?" is that **"you are comparing apples and oranges"**. C++ and PHP are two *completely separate* languages that simply happen to share a superficial similarity in syntax. – user Aug 04 '13 at 11:13

3 Answers3

14

I'm not sure what the rules are in PHP, but in C++, the order of individual sub-expressions isn't strictly defined, or as the technical term is, it is "unspecified" - in other words, the compiler is allowed to calculate b = a before or after it does a + b. As long as it does a + b and b = a before the subtraction. The use of "unspecified" behaviour allows the compiler to produce more efficient code in some cases, or simply that it's possible to build a compiler for some architectures.

It also means that if you have an expression that "recalculates" a value within the expression itself, and also using it elsewhere in the expression, you get unedefined behaviour (UB for short). UB means just that, the behaviour is not defined - almost anything could happen, including what you are seeing and many other alternatives (e.g. the compiler is allowed to produce 42 as a result as well, even if logic says the answer wouldn't be 42 in this case [it's the wrong question for that!]).

I would also suggest that if you want to swap two values, in PHP:

 $t = $a;
 $a = $b;
 $b = $t;

and in C++:

 #include <algorithm>

 std::swap(a, b); 

or if you insist on writing your own:

 int t = a;
 a = b;
 b = t; 

Trying to be clever and perform it "without temporary variable" is almost certainly going to make it slower than the use of a temporary - certainly in a compile language like C++ - in a interpreted language like PHP, creating a new variable may add a bit of extra overhead, but it's unlikely to be that big, compared to the extra effort in the logic required.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • There don't seem to be any rules in PHP. What seems to happen, however, is that subexpressions are evaluated in a left-to-right order. But it's not actually specified anywhere. – greyfade Oct 08 '13 at 17:17
3

C++ code is completely broken because of undefined behavior. (read and write b in one sequence point).

MAnyKey
  • 567
  • 4
  • 11
  • @FractalizeR Because PHP and C++ aren't the same language. So what is undefined behavior in C++ can be perfectly well defined in PHP, letting you write in one line what would ordinarily take two (or more) in C++. Or, equivalently, the same code written in two different languages need not do "the same thing" :) – Thomas Aug 04 '13 at 12:06
  • It isn't clear that anything is perfectly well defined in PHP. There is no language standard that I can see, just an online set of web pages saying "operators exist and they kind of do this", and lots of examples. – Ira Baxter Aug 05 '13 at 13:45
2

For PHP:

$a = 10;
$b = 20;
$a = ($a + $b) - ($b = $a);
//executes like thus
$a = (30) - ($b = $a);
$a = (30) - ($b = $a = 10); //new $a still not computed, using older $a
$a = (30) - (10);
$a = 20;
//then, $a=20 and $b = 10

This is totally related to Operator Precedence, this might be same in C or might not, it depends on precedence if unexpected behavior not occur.

  • As I think php is interpreting language so it may be that it converts parts of code into numeral expression, as a result it always gives the same result. Compared to compiling languages, what works with registers, memory addresses. – ST3 Aug 04 '13 at 08:17
  • 2
    @user2623967 Being compiled or interpreted doesn't enter into it. PHP has the advantage of having only one commonly used interpreter, so even undefined behavior is often predictable (although it might vary between versions and platforms). On the other hand there are many different C++ compilers and undefined behavior varies more between them. – JJJ Aug 04 '13 at 08:19