[英]Are a+=k and a=a+b different in c?
我試圖在沒有模板的情況下進行交換,但我遇到了這個問題。 a+=k
和a=a+b
不同嗎? 第一種情況有什么問題?
a += b-(b=a); // this print same value of two a and b.
a = a + b-(b=a); // this thing correctly swapped values.
兩者都會導致未定義的行為,因為您在沒有插入序列點的情況下訪問和修改b
:
6.5p2 :
如果對標量對象的副作用相對於對同一標量對象的不同副作用或使用同一標量對象的值進行的值計算而言是未排序的,則行為未定義。 如果一個表達式的子表達式有多個允許的排序,並且在任何排序中出現這種未排序的副作用,則行為是未定義的。
以下是使用 +/- 的方法(UB-free 僅適用於無符號數字類型,因為有符號 +/- 可能會導致未定義的溢出):
a+=b, b=a-b, a=a-b;
或使用 xor(始終無 UB):
a^=b, b^=a, a^=b;
Gcc 和 clang 似乎識別這兩種模式並通過臨時將它們編譯為交換,這是常見架構上最有效的方法: https : //gcc.godbolt.org/z/3W_22r
這兩個語句都會導致未定義的行為,因此不應期望它們給出相同的結果。
來自 C11 草案標准§6.5p2
如果對標量對象的副作用相對於對同一標量對象的不同副作用或使用同一標量對象的值進行的值計算而言是未排序的,則行為未定義。
在投稿代碼, (b=a)
是一個表達式,其值的值a
,但是具有的值分配的副作用a
到b
。 在兩個語句,的值(b=a)
其為值a
)從減去b
,但在這里b
是導致的值的值計算b
。 這兩個表達式之間沒有序列點,也就是說值計算b
是在(b=a)
之前還是之后排序是不確定的。 由於對副作用b
和的值計算b
是未測序在兩個陳述,都會導致不確定的行為。
最好避免這樣的“聰明”代碼。 在這種情況下,看似聰明的代碼具有未定義的行為; 在其他情況下,聰明的代碼對於必須維護代碼的其他人來說可能很難理解,甚至對於以后的你自己來說也是如此。 編寫清晰易懂且易於維護的代碼。 當您遇到性能問題並確定了罪魁禍首時,只需擔心優化。 編譯器很聰明,它們可以識別常見的習語,並且能夠在打開優化功能時為這些常見的習語生成接近最佳的代碼。 您很少需要逗號運算符或不直觀的 XOR 交換; 對於簡單的交換,這是編程中的一種常見操作,更喜歡明顯的解決方案,讓您的編譯器完成它的工作。
顯而易見的解決方案,使用與a
和b
相同類型的臨時變量,很容易理解,永遠不會有未定義的行為(甚至依賴於實現的行為),並且通常會被一個好的編譯器優化為更多性能優於來自善意的程序員微優化的代碼:
temp = a;
a = b;
b = temp;
來自C11 標准6.5.16.2.3
形式為
E1 op= E2
的復合賦值等效於簡單賦值表達式E1 = E1 op (E2)
,除了左值 E1 僅計算一次,並且對於不確定順序的函數調用,a 的操作復合賦值是一個單一的評估。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.