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 valuetrue
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 constant1
,false
which expands to the integer constant0
,[..]
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
Does It Make Any Sense to Use Inline Keyword With Templates
Right Way to Split an Std::String into a Vector≪String≫
How to Include Libraries in Visual Studio 2012
Explicit Specialization in Non-Namespace Scope
Is Main() Really Start of a C++ Program
Why Will Std::Sort Crash If the Comparison Function Is Not as Operator ≪
How to Change Mode from C++98 Mode in Dev-C++ to a Mode That Supports C++0X (Range Based For)
C++ Cross-Compiler from Windows to Linux
How to Install the Raspberry Pi Cross Compiler on My Linux Host Machine
Detect If Stdin Is a Terminal or Pipe
Why Does Integer Overflow on X86 With Gcc Cause an Infinite Loop
How to Convert a Lambda to an Std::Function Using Templates
How to Take a Screenshot in a Windows Application
C++ Pass an Array by Reference
How to Validate User Input as a Double in C++