Sign in to follow this  

Combining C++ bool and bitwise operators

This topic is 3320 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I had a discussion with a co-worker a few weeks back. It concerned the C++ data type bool and bitwise operators. He asserts that for the bool data type, bitwise operators are as good as logical boolean operators (his goal is to use bitwise xor as a logical operator in conditional statements...). Something about this rubs me the wrong way, but I can't quite put my finger on it. My instinct tells me to always use logical operators when not twiddling bits, but maybe i'm missing something. Does the C++ standard have anything to say about whether this is guaranteed to work or not? Do you have any other related thoughts/arguments?

Share this post


Link to post
Share on other sites
Bitwise operations on bools will cause the bools to be converted to integers, the operations to be done on those integers, and the result (assuming you're using it that way) to be converted back to bool. The result is that this will actually work. I wouldn't, though... it's too weird a smell. The boolean version of XOR is !=.

Share this post


Link to post
Share on other sites
Quote:
Original post by Sneftel
Bitwise operations on bools will cause the bools to be converted to integers, the operations to be done on those integers, and the result (assuming you're using it that way) to be converted back to bool. The result is that this will actually work. I wouldn't, though... it's too weird a smell. The boolean version of XOR is !=.
The only thing to watch out for is that != won't implicitly convert the two operands into booleans, while && and || will. Since bool is an integer type, something like if(intvar || boolvar) cannot simply be converted to if(intvar != boolvar) to change the or to xor, and instead needs to be changed to if((intvar != 0) != boolvar) or if(bool(intvar) != boolvar)

Share this post


Link to post
Share on other sites
Quote:
Original post by DevFred
The logical operators are short-circuit, the bitwise aren't. So the following is a bad idea:
if (p != 0 & p->x == 42)

Especially since it always returns false.

Share this post


Link to post
Share on other sites
Quote:
Original post by Sneftel
Quote:
Original post by DevFred
The logical operators are short-circuit, the bitwise aren't. So the following is a bad idea:
if (p != 0 & p->x == 42)

Especially since it always returns false.


(assuming it returns at all -- lol operator precedence -- it happens before *either* comparison)

Share this post


Link to post
Share on other sites
Quote:
Original post by Sneftel
Quote:
Original post by DevFred
The logical operators are short-circuit, the bitwise aren't. So the following is a bad idea:
if (p != 0 & p->x == 42)

Especially since it always returns false.


I think he meant that if p were 0 (or NULL) it would not short circuit, and go ahead and evaluate p->x, which would obviously be a seg-fault.

Share this post


Link to post
Share on other sites
Quote:
Original post by Sneftel
Quote:
Original post by DevFred
The logical operators are short-circuit, the bitwise aren't. So the following is a bad idea:
if (p != 0 & p->x == 42)

Especially since it always returns false.

Really? I don't think so. Please explain why.

The != and == operators have higher precedence than &, and since both comparisons yield a boolean, the & should work as expected. You just shouldn't dereference p with the -> operator if p is 0, that was my point.

Here is my test code:
#include <stdio.h>

struct Test
{
int x;
};

void f(struct Test *p)
{
if (p != 0 & p->x == 42)
printf("true");
else
printf("false");
}

int main(void)
{
struct Test a;
f(&a);
return 0;
}

And here is the assembler output for the function f:
_f:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
cmpl $0, 8(%ebp)
setne %al
movzbl %al, %edx
movl 8(%ebp), %eax
cmpl $42, (%eax)
sete %al
movzbl %al, %eax
andl %edx, %eax
testl %eax, %eax
je L2
movl $LC0, (%esp)
call _printf
jmp L1
L2:
movl $LC1, (%esp)
call _printf
L1:
leave
ret

It does exactly what I thought it did.

Share this post


Link to post
Share on other sites
Quote:
Original post by DevFred
The != and == operators have higher precedence than &

Indeed.. my mistake. It's been awhile since I did any bitwise stuff in C++, and I suppose I always aggressively parenthesize such things anyway. You win this round.

Share this post


Link to post
Share on other sites
Quote:
Original post by wack
I had a discussion with a co-worker a few weeks back. It concerned the C++ data type bool and bitwise operators. He asserts that for the bool data type, bitwise operators are as good as logical boolean operators (his goal is to use bitwise xor as a logical operator in conditional statements...).


For the most part, they are.

Quote:
Original post by wack
Something about this rubs me the wrong way, but I can't quite put my finger on it. My instinct tells me to always use logical operators when not twiddling bits, but maybe i'm missing something.


There are plenty of languages which fuse the two pardigms (that is, logical And, Or, Xor, and Not ops ARE defined as bitwise, with True defined as 0xFFFFFFFF for the strictly logical operators such as greater-than)

The compiler can (and will.. even VB6) refactor as it sees fit in the case of non-assignments such as conditionals, so this does not have any meaningfull performance impact.

Quote:
Original post by wack
Does the C++ standard have anything to say about whether this is guaranteed to work or not? Do you have any other related thoughts/arguments?


It works. Really.

As already mentioned, there would be no short-circuiting, but you can always spell-it-out with a nest (as VB6/VBA programmers have had to do since forever.)

Also, some type-safety is thrown out the window.. obviously.

Still further, a compiler may perform reduction-optimizations on logical expressions but not bitwise ones (or vise-versa.)


One area where there is a very strong reason to use bitwise ops is for Logical SWAR code. A 32-bit integer can give you a 32x performance advantage here, and then there is the 128-bit SSE registers.

Another area where bitwise can be useful is in leveraging truth tables. Low order truth tables (5 operands) can fit into integers.

I am guessing that you are unpracticed with using bitwise ops as replacements for logical ops by your apprehension to it. This is actualy an unfortunate side-effect for programmers of certain languages, such as C, which draw the distinction.

I don't know why your co-worker wants to use bitwise over logical. If its just because he thinks that he's clever, then thats not really a good enough reason.

Share this post


Link to post
Share on other sites
Quote:
Original post by Sneftel
Quote:
Original post by DevFred
The != and == operators have higher precedence than &

Indeed.. my mistake. It's been awhile since I did any bitwise stuff in C++, and I suppose I always aggressively parenthesize such things anyway. You win this round.

I blame unary operator& for making me think you were right, too.

Share this post


Link to post
Share on other sites

This topic is 3320 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this