Bool to Int Conversion

bool to int conversion

int x = 4<5;

Completely portable. Standard conformant. bool to int conversion is implicit!

§4.7/4 from the C++ 11 or 14 Standard, §7.8/4 from the C++ 17 Standard, §7.3.9/2 from the 20 Standard says (Integral Conversion)

If the source type is bool, the value false is converted to zero and
the value true is converted to one.


As for C, as far as I know there is no bool in C. (before 1999) So bool to int conversion is relevant in C++ only. In C, 4<5 evaluates to int value, in this case the value is 1, 4>5 would evaluate to 0.

EDIT: Jens in the comment said, C99 has _Bool type. bool is a macro defined in stdbool.h header file. true and false are also macro defined in stdbool.h.

§7.16 from C99 says,

The macro bool expands to _Bool.

[..] true which expands to the integer constant 1, false
which expands to the integer constant 0,[..]

Convert boolean to int in Java

int myInt = myBoolean ? 1 : 0;

^^

PS : true = 1 and false = 0

Convert boolean result into number/integer

Javascript has a ternary operator you could use:

var i = result ? 1 : 0;

How to convert bool to int efficiently?

It's not all that surprising that reading 4 bytes from a bool generates code that spills to memory first, then reloads, because that's a weird thing to do.

If you're going to mess around with unsafe pointer-casting for type-punning, surely you should be reading the bool into a same-sized integral type like unsigned char or uint8_t or whatever equivalent C# has, and then casting (or implicitly converting) that narrow type to int. Apparently that's Byte.

using System;
static unsafe int H(bool b)
{
return *(Byte*)&b;
}

asm on Sharplab, and see below for this inlining into a caller for H(a == b).

<Program>$.<<Main>$>g__H|0_0(Boolean)
L0000: mov eax, ecx
L0002: ret

So apparently the ABI / calling convention passes narrow args like "bool" sign- or zero-extended to 32-bit already. Or else this is more unsafe than I realize and will actually result in int values that aren't 0 or 1!

We get a movzx-load if we take a pointer-to-bool that's not already in a register:

static unsafe int from_mem(bool *b) 
{
return *(Byte*)b;
}
<Program>$.<<Main>$>g__from_mem|0_1(Boolean*)
L0000: movzx eax, byte ptr [rcx]
L0003: ret


Re: performance benefit

There were some questions raised in comments about which is actually better. (And some nonsensical performance claims about code-size and front-end fetch which I replied to in comments.)

If branching was better in general, C and C++ compilers would do that, but they don't. This is very much a missed optimization in current C# implementations; that branching asm is insane, IMO. Possibly / hopefully that goes away with 2nd-stage JITing for hot code-paths, in which case messing around with unsafe could make things worse. So there is some merit to testing real use-cases.

movzx eax, cl has zero latency on current Intel CPUs (Can x86's MOV really be "free"? Why can't I reproduce this at all?), or 1 cycle latency on AMD. (https://uops.info/ and https://agner.org/optimize/). So the only cost is 1 uop for the front-end, and a data dependency on the input. (i.e. the int value isn't ready for use by later instructions until the bool value is ready, like with normal operations such as +)

Branching has the possible upside of using the result now and verifying it was correct when the bool is actually available (branch prediction + speculative exec break the data dependency), but has the huge downside that branch mispredicts stall the pipeline for ~15 cycles, and wastes any work done since the branch. Unless it's very predictable, movzx is much better.

The most likely case for "very predictable" would be a value that never changes, in which case reading it should be cheap (unless it misses in cache) and out-of-order exec can do that nice and early, which would make movzx good and avoid using up space in the CPU's branch-predictor unnecessarily.

Branching on a bool to create a 0 / 1 is basically using branch prediction to do value-prediction. It's certainly possible that it's a good idea in a few rare cases, but it's not what you want by default.


C and C++ compilers can use movzx when widening a bool to an int because the object-representation of a bool is guaranteed / required by the ABI to be 0 or 1. I assume that's the case in most C# implementations as well, not just a byte with 0 / some-non-zero value that might not be 1.

(But even if you did have an arbitrary non-zero value, the normal way to booleanize it to 0 / 1 is xor eax, eax / test cl,cl / setnz al. i.e. to implement int retval = !!x for an integer byte x.)



Real use-case when inlining:

static int countmatch(int total, int a, int b) {
//return total + (a==b); // C
return total + H(a == b);
}

Sharplab

<Program>$.<<Main>$>g__countmatch|0_2(Int32, Int32, Int32)
L0000: cmp edx, r8d
L0003: sete al
L0006: movzx eax, al
L0009: add eax, ecx
L000b: ret

Pretty normal code-gen; what you'd expect from a C compiler, just one missed optimization: should use xor eax,eax / cmp / sete al to take the movzx zero-extension off the critical path for latency. (AL and EAX being part of the same register mean that even on Intel CPUs, mov-elimination doesn't apply). Clang, gcc, and MSVC do this (https://godbolt.org/z/E9fKhh5K8), although older GCC sometimes has trouble avoiding the movzx in other more complicated cases, perhaps minimizing register pressure.

Sharplab doesn't seem to have AArch64 output to let you see if it can compile to cmp w1, w2 / cinc w0, w0, eq like C compilers do. (As well as conditional-select, ARM64 provides a csinc conditional select-increment, which it uses with the zero-register to build cset (x86 setcc) and cinc (add a FLAG condition).) I wouldn't be too optimistic; I'd guess probably still materializing a bool into a register and adding it.

static int countmatch_safe(int total, int a, int b) {
return total + Convert.ToInt32(a == b);
}

Without unsafe in C#, the silly code-gen inlines and still materialized a boolean for add, instead of branching around an inc. This is even worse than if(a==b) total++; which does compile the way you'd expect.

<Program>$.<<Main>$>g__countmatch_safe|0_3(Int32, Int32, Int32)
L0000: cmp edx, r8d
L0003: je short L0009
L0005: xor eax, eax
L0007: jmp short L000e
L0009: mov eax, 1
L000e: add eax, ecx
L0010: ret

C++ casting bool to int - standard

The way you are using it exhibits UB, because you write outside of the bool variable's boundaries AND you break strict aliasing rule.

However, if you have a bool and want to use it as a an int (this usually happens when you want to index into an array based on some condition), the standard mandates that a true bool converts into 1 and false bool converts into 0, no matter what (UB obviously excluded).

For example, this is guaranteed to output 52 as long as should_add == true.

int main(){
int arr[] = {0, 10};
bool should_add = 123;
int result = 42 + arr[should_add];
std::cout << result << '\n';
}

C++ - Bool to int conversion bug

You should inspect where the bool is set. Notably, the C++ standard does not guarantee that any memory accessed as a bool value will convert to 1 if the memory was not exactly 0 - it only guarantees that a bool of value true will convert to 1. As mentioned here, it is possible for a bool to have a value that is neither true nor false as a consequence of undefined behavior. That may seem obvious (UB after all) but it is also surprising (apparently even by the standard authors' standards).

Here is a practical demonstration of this, using memcpy:

#pragma pack(1)
struct ObjectType
{
float float_data = -3.0f;
bool bool_data = false;
int integer_data = 2;
};

volatile unsigned char x = 7;

float test()
{
// Don't actually do this, it is for demonstration only.
std::array<unsigned char, sizeof(ObjectType)> data = { 0, 0, 0, 0, /**/ x, /**/ 2, 0, 0, 0 };

ObjectType obj;
memcpy(&obj, data.data(), sizeof(obj));

return foo(obj);
}

http://coliru.stacked-crooked.com/a/0221a82a6d35e18b <- runtime evaluation yields 14

http://coliru.stacked-crooked.com/a/982ff8e4d7503f08 <- compile-time evaluation yields 2

Indeed, inspecting the binary shows that foo literally interprets the bool as an integer and multiplies with it for gcc. I would conclude that gcc achieves standard conformance by only ever storing a 1 or 0 whenever it stores to a bool, thus behaving as if true is only ever converted to 1 (as long as you never force a bool into a diferent state than true or false).

Better way to convert an int to a boolean

I assume 0 means false (which is the case in a lot of programming languages). That means true is not 0 (some languages use -1 some others use 1; doesn't hurt to be compatible to either). So assuming by "better" you mean less typing, you can just write:

bool boolValue = intValue != 0;

How do I convert a boolean to an integer in Rust?

Cast it:

fn main() {
println!("{}", true as i32)
}


Related Topics



Leave a reply



Submit