2010-08-17 89 views
29

我有必要代碼的形式爲什麼C沒有邏輯賦值運算符?

a = a || expr; 

其中expr應評估和結果分配給a當且僅當a沒有設置的聲明。這依賴於邏輯OR的短路能力。

寫上面會,當然是

a ||= expr; 

但較短的方式(讓我吃驚的)C沒有邏輯賦值運算符。

所以我的問題是雙重的。首先,在標準C中寫出第一條語句的方法更短(三元運算符更糟糕 - a = a ? a : expr要求我拼出a三倍)。

其次,爲什麼C中沒有邏輯賦值?我能想到的可能原因有:

  • 它使語法難以解析?
  • 處理這些情況下的短路有一些微妙之處嗎?
  • 它被認爲是多餘的(但不是反對所有運營商分配的爭論?)

編輯

請解開這個問題,因爲:

  • 它被連接到的問題(作爲所謂的重複)尚未得到答覆。該問題的(接受的)答案指出||=不存在,因爲重複了|=的功能。這是錯誤的答案。 |=不會短路。

  • C和C++不是相同的語言。我想知道爲什麼C沒有它。事實上,像C++這樣的派生語言,特別是Java(它沒有像Edmund的答案中提到的遺留代碼的問題)的事實使得這個問題更加有趣。

EDIT 2

現在好像我的原意是錯誤的。在聲明a = a || expr(其中a是整數,expr返回一個整數值,首先將aexpr隱式轉換爲「布爾值」,然後將「布爾值」值分配給a。這將不正確 - 整數價值將會喪失。謝謝,延斯和埃德蒙。

因此,對於問題的第一部分,正確的方式,而不是替代品:),編寫我的意圖是:

if (!a) a = expr; 

a = a ? a : expr; 

他們應該優化相同(我認爲)雖然個人我寧願第一個(因爲它有一個a鍵入)。

但是,問題的第二部分仍然存在。 Jens和Edmund關於a ||= expr中含糊不清的論點同樣適用於a = a || expr。分配情況下,可以簡單地被視爲正常之一:

  • 轉換a爲布爾
  • 如果這是真的,則整個表達式的值變爲等於a
  • 布爾值否則評估expr ,將結果轉換爲布爾值,分配給a,並將其返回

以上步驟似乎對於賦值和正常情況都是相同的。

+1

此問題*不是*上述「可能重複」的確切副本。那個問題問爲什麼沒有'|| ='的語法縮寫,等等。這個問題詢問爲什麼C不允許通過布爾運算符來攜帶非布爾運算符。 – Edmund 2010-08-17 09:41:43

+1

我打算髮表一個答案:如果那些短路工作會很好。 有一個選項'if(!a)a = expr;'這個選項很清楚簡潔。 至於技巧,請注意,布爾的加法和乘法分別產生OR和AND函數,只要你不需要短路或強制轉換爲'bool','+ ='和'* ='分別執行'|| ='和'&& ='。 – Potatoswatter 2010-08-17 09:43:10

+1

由於這是過早關閉,我在評論中回答。我認爲這不存在,因爲它的解釋是不明確的。在'a | = expr'中應該賦值'expr'的結果還是其邏輯值? 「a | = expr」的整體類型,「int」,「a」的類型或者「a」和「expr」的結果應該是什麼?我不認爲這些問題有一個直接的解決方案,所以任何可能已經考慮過這個問題的人都已經很快放棄了。我個人會選擇'a =(a?a:expr)'並讓編譯器優化分配。 – 2010-08-17 12:44:57

回答

3

我想簡單的答案是||是一個布爾運算符:在C中,「布爾值」是0或1.操作數隱式轉換爲布爾值(我沒有檢查過這是規範實際說的,但它是C的行爲),結果是一個布爾值。

改變語義以支持這種模式可能是可行的 - 直到有人依靠||來完成它始終完成的任務。

+3

C中沒有'boolean'類型,所以操作數不會被轉換爲'boolean','||'的結果並且'&&'不是'boolean'。 – qrdl 2010-08-17 10:08:22

+2

@qrdl關於'boolean'(雖然C99具有'_Bool'),但'&&','||'(和'!')被定義爲0或1的情況是對的。請參閱C99標準§6.5 .13和§6.5.14。 – schot 2010-08-17 10:47:17

+1

謝謝。我使用「引號」表示這就是它的近似含義。如果我想要bean指的是神祕的'boolean'類型,我就會這樣表示它。我的答案整體而言表現爲行爲,而不是抽象的規範。 – Edmund 2010-08-17 10:59:38

3

由於運算符||&&的返回類型與其左側參數的類型不同。

||&&返回類型總是int ,而左邊的參數可以是任何一體的,浮點或指針類型。操作數也不必是同一類型的。因此將x ||= y定義爲x = x || yx &&= yx = x && y與其他擴充分配一致將不能將結果存儲在大多數類型的參數中。

你可以想出其他的定義,例如x ||= y作爲if(!x) x = yx &&= y作爲if(!y) x = y,但那不會很明顯,它不是有用,所以它不包括在內。

在C++中,它是bool

3

我找不到任何特殊的原因,爲什麼運營商不存在(在C99)。

所以我能找到的唯一原因是,在C89中沒有布爾類型,而這些布爾運算符僅用於if's。

例子:

int i = 5; 

/* This should not make any difference, 
    since or'ing with false, shouldn't change 
    the value... dib di dib diddy...*/ 
i ||= 0; /* Actually: i = i || 0, which gives 'true' */ 

i現在是'1」,這對於大多數人來說是相當直覺。

這個操作符顯然不帶任何清除或編碼改進沒有布爾類型,這將使​​認識或與另一個。

在我看來,a ||= b;作爲if(!a) a = b;的實施將是非常簡單的,並已通過例如實現。 Lua中。

所以你的問題似乎有點,爲什麼C被設計了它的方式。 如果這個問題是關於C++的,那麼你可以問Bjarne Stroustrup並問他到底是怎麼回事。既然事實並非如此,那麼在我看來,這似乎是一種死路一條,因爲標準已經寫得相當一段時間了,而且你不能再問人了,爲什麼要這樣做。另一方面,這個不完整的操作符集應該(在我看來)aleardy已經使用了與你的類似的符號整體,因爲在我看來,沒有任何理由反對它。

我希望我能幫一點點。

5

a ||= expr由於其等價物a = a || expr的短路評估而存在問題。

要有a ||= expr功能像a = a || expr考慮OP的斷言:

「在聲明中a = a || expr ...,第一a和EXPR將被隱式轉換爲 」布爾「,」

這是不正確的。 expr將不會被轉換,如果a評估爲true。如果expr類似於scanf()rand()或某些影響程序狀態的函數,這將會產生變化。

諸如a ||= scanf("%d", &i) != 1;之類的代碼只會嘗試在a中掃描具有錯誤值的數據。儘管可以用這種方式來擴展語言,但是對當前的||&&集合的其他短路操作可能會導致比明確簡化更多的編碼問題。

另一方面:一種快速(如果模糊處理)編寫代碼的方法,其中函數在出錯時返回非零代碼。

// Perform functions until an error occurs. 
bool error = foo1(); 
error &&= foo2(); // Only valid if C was extended with &&= 
error &&= foo3();