看板 C_and_CPP 關於我們 聯絡資訊
: → 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