2012年4月22日 星期日

C&C++: Re: [問題] 請教如何只用x,y兩變數來交換彼此數值

 作者  LPH66 (-858993460)                                     看板  C_and_CPP
 標題  Re: [問題] 請教如何只用x,y兩變數來交換彼此數值
 時間  Mon Apr 11 23:40:29 2011
───────────────────────────────────────

: → littleshan:不要這樣寫!這是 implementation-defined behavior     04/11 15:48
: → littleshan:就是十誡之八啦                                       04/11 15:49
基本上這個寫法的確是 implementation-defined behavior

不管有沒有加括號都一樣

事情是這樣的

a ^= b ^= a ^= b;
1 2 3 4 5 6 7

這樣寫的人想要做的事的順序是
                                值為
(7) 取 b 的值                   原來的 b
(5) 取 a 的值                   原來的 a
(6) 做 (5)^(7) 並把值放回 a 去  原來的 a^b
(3) 取 b 的值                   原來的 b
(4) 做 (3)^(6) 並把值放回 b 去  原來的 a
(1) 取 a 的值                   原來的 a^b
(2) 做 (1)^(4) 並把值放回 a 去  原來的 b

但有些 compiler (如我手上的 g++ 4.1.0 for win) 會編成這個順序

                                值為
(1) 取 a 的值                   原來的 a
(3) 取 b 的值                   原來的 b
(5) 取 a 的值                   原來的 a
(7) 取 b 的值                   原來的 b
(6) 做 (5)^(7) 並把值放回 a 去  原來的 a^b
(4) 做 (3)^(6) 並把值放回 b 去  原來的 a
(2) 做 (1)^(4) 並把值放回 a 去  一定是 0

結果是原來 a 的值在 b  但 a 卻變成 0 了

問題在於

雖然這個式子的確是分析成

     ^= (2)
   /    \
 a      ^= (4)
(1)   /    \
    b      ^= (6)
   (3)   /    \
       a        b
      (5)      (7)

這個樣子  但在計算 a ^= b 時  a b 取值的順序卻是 implementation-defined

也就是在上面那棵語法樹的後序走訪中先走左子樹還是先走右子樹

如果先走左子樹  就是 1 3 5 7 6 4 2 的順序

    先走右子樹  就是 7 5 6 3 4 1 2 的順序

而這兩個順序  上面我也寫出來了

後者是順利交換沒錯  前者卻是把 a 搬到 b 後把 a 炸成 0 !

所以結論是千萬不要用這個寫法

---
其實簡單一句話就是十三誡之八裡說的

    你不可以在一個運算式(expression)中,對一個基本型態的變數修改其值
    超過一次以上。否則,將導致未定義的行為(undefined behavior)

如果真要用 xor 來交換  乖乖寫三條

x ^= y; y ^= x; x ^= y;

就什麼事都沒有....

當然最好的寫法還是 int temp = x; x = y; y = temp; 就是了

--
  'You've sort of made up for it tonight,' said Harry. 'Getting the
sword. Finishing the Horcrux. Saving my life.'
  'That makes me sound a lot cooler then I was,' Ron mumbled.
  'Stuff like that always sounds cooler then it really was,' said
Harry. 'I've been trying to tell you that for years.'
                               -- Harry Potter and the Deathly Hollows, P.308

--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 140.112.30.142
推 attomahawk:推薦這棵 語法樹!                                    04/12 00:02
推 glennchen:好強大                                                04/12 00:07
推 loveme00835:不管多炫, 在可讀性上永遠是個失敗品, 是禁忌          04/12 00:09
推 james732:原來如此!                                             04/12 00:12
推 VictorTom:推語法樹:)                                            04/12 00:16
→ bibo9901:借問一下, 那寫成 a+=b; b=a-b; a-=b; 可以嗎             04/12 00:39
推 purpose:有緩衝區溢位的風險,如 a = INT_MAX; b = 1;              04/12 00:41
→ purpose:沒有緩衝區,打太快了                                    04/12 00:41
推 littleshan:overflow 是 undefined behavior                       04/12 00:43
推 xatier:語法樹! 推                                              04/12 07:36
推 wanwan2:讚!!                                                    04/12 08:40
推 genghiskii:3F正解                                               04/12 10:08
推 j094097:大推                                                    04/12 21:23
推 yauhh:都忘了這件事,果然imperative就怕太依賴state                04/12 21:40
推 h520:用樹講解好清楚啊!! 大推                                    04/14 13:42

沒有留言:

張貼留言