c语言布尔变量逻辑运算,在C ++中对布尔值使用按位运算符
有什么理由不對C ++中的"布爾"值使用按位運算符&,|和^?
有時,我遇到兩種情況之一,即我想完全滿足兩個條件之一(XOR),因此我只是將^運算符放入條件表達式中。 有時我還希望評估條件的所有部分,無論結果是否正確(而不是短路),因此我使用&和|。 有時我還需要累積布爾值,并且&=和| =可能非常有用。
在執行此操作時,我有些挑剔,但是代碼仍然比其他方法有意義且更簡潔。 有沒有理由不將其用于布爾? 是否有任何現代編譯器為此帶來不好的結果?
如果從提出此問題以來您已經對C ++有了足夠的了解,那么您應該返回并接受當前答案,并接受Patrick Johnmeyers答案,以正確解釋短路差異。
總的說來,因為人們質疑這是否是一個好主意。 如果您關心單元測試的分支覆蓋范圍,那么減少分支是可取的。 按位運算符對此很有用。
||和&&是布爾運算符,并且保證內置運算符將返回true或false。沒有其他的。
|,&和^是按位運算符。當您操作的數字域僅是1和0時,它們是完全相同的,但是在布爾值不嚴格地為1和0的情況下(如C語言那樣),您可能會遇到某些錯誤不想。例如:
BOOL two = 2;
BOOL one = 1;
BOOL and = two & one; ? //and = 0
BOOL cand = two && one; //cand = 1
但是,在C ++中,保證bool類型只能是true或false(它們分別隱式地轉換為1和0),因此從這種立場出發,您不必擔心,但是人們不習慣在代碼中看到這樣的事實,為不這樣做提供了很好的理由。只需說b = b && x并完成它。
在C ++中,沒有邏輯異或運算符^^這樣的東西。對于兩個參數,布爾值!=都具有相同的作用,但是如果兩個參數都不是布爾值,則可能會很危險(因為將^用于邏輯xor)。不知道如何被接受...
回想起來,那真是愚蠢。無論如何,將示例更改為&&以解決問題。我發誓我過去曾經使用過^^,但事實并非如此。
感謝您重新解決該問題;刪除了我的評論。
自10年以來,C的布爾類型只能為0或1。 _Bool
無論如何。我認為!! two&!! one將解決第一個問題,且= 0。 !將任何非零的東西變成1。
帕特里克(Patrick),因為您已經接受了答案,所以如果您要添加有關使用&=和| =進行累加的信息,那將是很好的。閱讀完整個線程并進行了一些測試之后,我檢查并了解到gcc在bool passed_tests_ = true; passed_tests_ &= 8;之后給出了false,這意味著我的測試之一很脆弱,無法稍后編輯...(尋找這就是將我帶到這里的原因)
即使對于傻瓜來說,它們也不一樣,因為它們不會短路
是的,我堅信只有在將"當您操作的數字域僅為1和0時,它們完全相同"更改為"當您正在操作的數字域僅為1時",這才是不可接受的答案。和0,唯一的區別是按位運算符不會短路。"前一個陳述完全是錯誤的,因此與此同時,我對這個答案不滿意,因為它包含了那句話。
兩個主要原因。簡而言之,請仔細考慮。這樣做可能有充分的理由,但是如果您的注釋中有非常明確的內容,因為它可能很脆弱,而且就像您自己說的那樣,人們通常不習慣看到這樣的代碼。
按位異或!=邏輯異或(0和1除外)
首先,如果要對false和true(或0和1,作為整數)以外的值進行運算,則^運算符可以引入不等同于邏輯xor的行為。例如:
int one = 1;
int two = 2;
// bitwise xor
if (one ^ two)
{
// executes because expression = 3 and any non-zero integer evaluates to true
}
// logical xor; more correctly would be coded as
// ? if (bool(one) != bool(two))
// but spelled out to be explicit in the context of the problem
if ((one && !two) || (!one && two))
{
// does not execute b/c expression = ((true && false) || (false && true))
// which evaluates to false
}
感謝用戶@Patrick首次表達了這一點。
操作順序
其次,|,&和^作為按位運算符,不會短路。此外,可以通過優化編譯器對在單個語句中鏈接在一起的多個按位運算符(即使帶有顯式括號)進行重新排序,因為所有3個操作通常都是可交換的。如果操作順序很重要,則這一點很重要。
換一種說法
bool result = true;
result = result && a() && b();
// will not call a() if result false, will not call b() if result or a() false
不會總是得到與以下結果相同的結果(或最終狀態)
bool result = true;
result &= (a() & b());
// a() and b() both will be called, but not necessarily in that order in an
// optimizing compiler
這一點特別重要,因為您可能無法控制方法a()和b(),或者其他人可能后來出現并在以后不理解依賴項的情況下對其進行了更改,并導致了令人討厭的(通常僅是發布生成)錯誤。
如果在一種情況下而不是在另一種情況下轉換為bool,這不是一個真正的公平比較。在這兩種情況下,轉換為bool都是使其工作的原因,以及它為什么脆弱的原因(因為您必須記住它)。
短路的解釋是為什么這絕對應該成為公認的答案;為什么?帕特里克(Patricks)的回答(錯誤...另一位叫帕特里克(Patrick)的帕特里克(Patrick))完全錯誤地說"當您操作的數字的域只有1和0時,它們是完全相同的"
我認為
a != b
是你想要的
的確是+1。但是沒有此運算符的分配版本(可以說是!==),因此,如果要計算bool值序列的XOR,則需要在循環主體中寫入acc = acc!= condition(i);。編譯器可能可以像處理!==一樣有效地處理此問題,但有些人可能會發現它看起來不太好,并且傾向于將布爾值添加為整數,然后測試總和是否為奇數。
揚起的眉毛應該告訴你足以停止這樣做。您無需為編譯器編寫代碼,而是先為其他程序員編寫代碼,然后再為編譯器編寫代碼。即使編譯器正常工作,也不會讓其他人感到驚訝-按位運算符是針對位操作而不是布爾值。
我想你也用叉子吃蘋果嗎?它有效,但它會讓人們感到驚訝,因此最好不要這樣做。
是的,這應該是最佳答案。遵循最少驚訝的原則。做異常事情的代碼更難閱讀和理解,而且閱讀的頻率遠高于編寫的頻率。不要使用像這樣的可愛技巧。
我在這里是因為我的同事對布爾使用按位"和"運算符?,F在,我正在花時間嘗試了解這是否正確。如果他不這樣做,我現在會做些更有用的事情-_-。如果您珍惜同事的時間,請不要對布爾使用按位運算符!
位級運算符的缺點。
你問:
Is there any reason not to use the bitwise operators &, |, and ^ for"bool" values in C++?
是的,邏輯運算符(即內置的高級布爾運算符!,&&和||)具有以下優點:
確保將參數轉換為bool,即轉換為0和1序數值。
保證短路評估,一旦知道最終結果,表達式評估就會停止。
這可以解釋為具有True,False和Indeterminate的樹值邏輯。
可讀的文本等效項not,and和or,即使我自己不使用它們也是如此。
正如讀者Antimony在評論中指出的那樣,位級運算符還具有其他令牌,即bitand,bitor,xor和compl,但在我看來,它們比and,or和< 5233>。
簡而言之,高級運算符的每個此類優點都是位級運算符的缺點。
特別是,由于按位運算符缺少將參數轉換為0/1的結果,因此例如1 & 2 0,而1 && 2 true。按位異或的^也會以這種方式出現錯誤。布爾值1和2相同,即true,但被視為位模式卻有所不同。
如何在C ++中表達邏輯或。
然后,您為問題提供了一些背景知識,
I sometimes run into situations where I want exactly one of two conditions to be true (XOR), so I just throw the ^ operator into a conditional expression.
好吧,按位運算符的優先級高于邏輯運算符。這尤其意味著在諸如
a && b ^ c
您會得到可能意外的結果a && (b ^ c)。
而是只寫
(a && b) != c
更簡潔地表達您的意思。
對于多參數,要么/或者沒有執行該工作的C ++運算符。例如,如果您編寫a ^ b ^ c,則該表達式不是說a,b或c為真的表達式。而是說,a,b和c的奇數為真,可能是其中的1個或全部3個
要表達一般性,或者當a,b和c的類型為bool時,只需編寫
(a + b + c) == 1
或使用非bool參數將其轉換為bool:
(!!a + !!b + !!c) == 1
使用&=累積布爾結果。
您進一步闡述,
I also need to accumulate Boolean values sometimes, and &= and |=? can be quite useful.
好吧,這相當于分別檢查是否滿足所有條件或任何條件,并且de Morgans法則告訴您如何從一個條件轉到另一個條件。即您只需要其中之一。原則上,您可以將*=用作&&=運算符(因為發現了很好的老喬治·布爾,邏輯AND可以很容易地表示為乘法),但是我認為這會使代碼的維護者感到困惑,甚至可能引起誤解。
還請考慮:
struct Bool
{
bool ? ?value;
void operator&=( bool const v ) { value = value && v; }
operator bool() const { return value; }
};
#include
int main()
{
using namespace std;
Bool a ?= {true};
a &= true || false;
a &= 1234;
cout << boolalpha << a << endl;
bool b = {true};
b &= true || false;
b &= 1234;
cout << boolalpha << b << endl;
}
使用Visual C ++ 11.0和g ++ 4.7.1的輸出:
true
false
結果不同的原因是位級別&=不能將其右手邊參數轉換為bool。
那么,您希望使用&=這些結果中的哪一個?
如果是前一個true,則最好定義一個運算符(例如上述形式)或命名函數,或者使用右側表達式的顯式轉換,或完整編寫更新。
按位運算符也具有文本等效項
@Antimony:我最初不理解該注釋,但是是的,位級操作具有備用標記bitand,bitor,xor和compl。我認為這就是為什么我使用"可讀"的資格。當然,例如compl 42是主觀的。 ;-)
據我所知,邏輯運算符可以重載其他參數類型(盡管通常不會重載),所以第一點"保證將參數轉換為bool"只是約定的結果,并不保證C ++語言實際上給你。
@MarcvanLeeuwen:可能您的視覺子系統沒有注意到"內置的高級布爾運算符!,&&和||"。沒錯,這些運算符可以重載,然后一個主要問題是語義會微妙地更改,不再需要短路評估。但這就是重載的問題,而不是內置運算符的問題。
是的(我確實很想念)。但是,該語句仍然具有誤導性,因為您只是在說那些運算符采用布爾型參數。當(且僅當)選擇了運算符的內置版本時,編譯器將插入參數的轉換。同樣,內置的(高級)無符號整數加法運算符+保證將其參數轉換為unsigned,但這不會阻止unsigned int n=-1; n+=3.14;實際使用double(或者是float?)加法運算。 (比較您的&=示例。)
@MarcvanLeeuwen:對不起,現在您是看似胡說八道的辯護。但是,您可能沒有意識到操作符不能為內置類型重載。關于內置運算符的保證是關于內置運算符的保證。
與Patrick的答案相反,C ++沒有用于執行短路異或的^^運算符。如果想一想,使用^^運算符無論如何都沒有任何意義:使用異或,結果始終取決于兩個操作數。但是,在比較1 & 2和1 && 2時,Patrick關于非bool"布爾"類型的警告同樣適用。 Windows GetMessage()函數就是一個典型的例子,該函數返回三態bool:非零,0或-1。
使用&代替&&和|代替||并非罕見的錯別字,因此,如果您故意這樣做,則應添加注釋以說明原因。
不管是否考慮短路,^^運算符仍然有用。它將a)在布爾上下文中評估操作數,并b)保證返回1或0。
@CraigMcQueen。定義inline bool XOR(bool a,bool b) { return a!=b; }并獲得所需的內容很簡單,只是它是一個函數而不是(中綴)運算符?;蛘?#xff0c;您可以直接使用!=或重載具有此含義的其他運算符,但是當然,您需要非常小心,以免意外使用相同名稱的意外重載。偶然地,||和&&返回true或false,而不是1或0。
似乎!,||和&&在布爾上下文中評估其參數的事實僅是因為這些運算符很少重載以接受其他類型。據我所知,該語言確實允許此類重載,因此不能保證在布爾上下文中評估參數。
帕特里克(Patrick)提出了要點,我不再重復。但是我可能會建議通過使用命名良好的布爾變量將``if''語句盡可能地簡化為可讀的英語,例如,這是使用布爾運算符,但您也可以使用按位并適當地命名布爾值:
bool onlyAIsTrue = (a && !b); // you could use bitwise XOR here
bool onlyBIsTrue = (b && !a); // and not need this second line
if (onlyAIsTrue || onlyBIsTrue)
{
.. stuff ..
}
您可能會認為使用布爾值似乎是不必要的,但這在兩個主要方面有幫助:
您的代碼更容易理解,因為'if'條件的中間布爾值使條件的意圖更加明確。
如果您使用的是非標準或意外的代碼(例如布爾值的按位運算符),人們可以更輕松地了解執行此操作的原因。
編輯:您沒有明確地說您想要'if'語句的條件(盡管這似乎很有可能),這是我的假設。但是我對中間布爾值的建議仍然存在。
IIRC,許多C ++編譯器會在嘗試將按位運算的結果強制轉換為布爾值時發出警告。您將必須使用類型轉換來使編譯器滿意。
在if表達式中使用按位運算將引起相同的批評,盡管編譯器可能不會這樣做。任何非零值都將被視為true,因此" if(7&3)"之類的值將為true。這種行為在Perl中是可以接受的,但是C / C ++是非常明確的語言。我認為Spock的眉毛是盡職調查。 :)我將附加" == 0"或"!= 0"以使其完全清楚您的目標是什么。
但是無論如何,這聽起來像是個人喜好。我將通過lint或類似工具運行代碼,看看它是否還認為這是不明智的策略。就個人而言,它讀起來就像是一個編碼錯誤。
您的帖子激勵我進行測試,而gcc并未發出警告! Bummer,因為我將使用該警告來證明讓我運行&=來累積布爾結果,因此相信其他人在以后更改我的測試時會看到該警告。我的代碼對于偶數整數也將失敗,因為它們的取值為0 / false-沒有警告!是時候重構...
對布爾使用按位運算有助于節省處理器不必要的分支預測邏輯,這是由于邏輯運算引入了" cmp"指令所致。
用按位運算(所有操作數均為bool)替換邏輯會生成提供相同結果的更有效代碼。理想情況下,效率應超過使用邏輯運算進行訂購時可以利用的所有短路優勢。
盡管程序員應該以注釋的理由來注釋它,但是這可能會使代碼有點不可讀。
總結
以上是生活随笔為你收集整理的c语言布尔变量逻辑运算,在C ++中对布尔值使用按位运算符的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Qt那些事儿-Qt基础教程
- 下一篇: 计算机图形学教程动画实验报告,计算机图形