172

How portable is this conversion. Can I be sure that both assertions pass?

int x = 4<5;
assert(x==1);

x = 4>5;
assert(x==0);

Don't ask why. I know that it is ugly. Thank you.

pic11
  • 14,267
  • 21
  • 83
  • 119
  • 1
    Why don't your change the first expression? You can write `assert(x!=0)`. Even if bool(true) converts portable to the int(1), the "not false" asserts has a more readable expression. – harper Mar 20 '11 at 16:48
  • 2
    Why not: `assert( 4 < 5);` and `assert(!( 4 > 5));` – Martin York Mar 20 '11 at 17:15
  • 4
    @harper: Using the required value of a comparison expression is perfectly reasonable. – R.. GitHub STOP HELPING ICE Mar 20 '11 at 22:17
  • @R._ When the question is if the bool-to-int conversion gives a reasonable result, I would not rely on this. When the author has a doubt that this requirement is fullfilled, the reader could get the same problem. Especially because the value of x is not the condition to check but only a intermediate result. – harper Mar 21 '11 at 06:32
  • 4
    I would probably write `(4 < 5) ? 1 : 0` if I really need to convert a boolean to 0 or 1. A good compiler will likely produce the same machine code and it's clearer for a human reader. – ollb Mar 26 '11 at 13:08
  • @ollb I think *most* of modern compilers are good enough to optimize this. – eonil Mar 14 '14 at 20:21
  • @R..GitHubSTOPHELPINGICE: what's the "stop helping ice" about? – Thomas Weller Apr 19 '21 at 12:10
  • 1
    [Conversion rules on cppreference](https://en.cppreference.com/w/cpp/language/implicit_conversion#Integral_conversions) – Alexander Malakhov Sep 14 '22 at 16:02

4 Answers4

265
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,[..]

Thomas Weller
  • 55,411
  • 20
  • 125
  • 222
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 14
    Regardless of the version of C language and availability of `bool`/`_Bool` type, relational operators in C produce `int`, not `bool`. I.e. even in C99, relational operators still produce `int`. – AnT stands with Russia Mar 20 '11 at 18:09
  • Regardless whether implicit bool -> int conversion is in standard, it may or may not be confusing when actually used in code, compared to actual type, used without conversion. – Smar Sep 09 '22 at 07:21
60

You tagged your question [C] and [C++] at the same time. The results will be consistent between the languages, but the structure of the the answer is different for each of these languages.

In C language your examples has no relation to bool whatsoever (that applies to C99 as well). In C language relational operators do not produce bool results. Both 4 > 5 and 4 < 5 are expressions that produce results of type int with values 0 or 1. So, there's no "bool to int conversion" of any kind taking place in your examples in C.

In C++ relational operators do indeed produce bool results. bool values are convertible to int type, with true converting to 1 and false converting to 0. This is guaranteed by the language.

P.S. C language also has a dedicated boolean type _Bool (macro-aliased as bool), and its integral conversion rules are essentially the same as in C++. But nevertheless this is not relevant to your specific examples in C. Once again, relational operators in C always produce int (not bool) results regardless of the version of the language specification.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • 2
    That is right, there is no bool in K&R C. I re-tagged my question as C99. – pic11 Mar 20 '11 at 17:42
  • @pic11: There was no need to retag anything. It has nothing to do with K&R or any other C. Even though there's `bool` in C99, the relational operators still produce `int` in C99, not `bool`. So, if it is specifically relational operators you are interested in (as in your examples), the issue still has nothing to do with `bool`. – AnT stands with Russia Mar 20 '11 at 18:05
  • Now I get it. The result of relation operator implicitly convertible to int. This is true in C, C99 and C++. Re-targed again. – pic11 Mar 20 '11 at 19:14
  • 4
    @pic11: No, you don't get it. In C, including C99, the result of a comparison operator is an `int`, not a `bool`. **No conversion happens.** – R.. GitHub STOP HELPING ICE Mar 20 '11 at 22:20
  • Is there any standards-conforming way via which a language could have a type which behaves like `bool` but does not allow its address to be taken? Many embedded systems make use of such types (often declared using the identifier `bit`). On e.g. a mid-range PIC, `if (bitVar1) bitVar2=1;` would be two instructions; optimal coding for `if (byteVar1) byteVar2=1;` would be at least four (on many compilers, probably five). Such types can thus offer a major performance boost. – supercat Jan 25 '14 at 16:57
  • @supercat: Would you please elaborate on how the "bit" version can be implemented in less instructions than the "byte" version? On the modern x84 platform the "byte" version can easily be implemented in two instructions: `cmp` and `setz` (or something similar, depending on where `byteVar1` is stored). On top of that, if additional information is available about the value of `byteVar1`, extra optimizations might be possible – AnT stands with Russia Jan 27 '14 at 16:54
  • @AndreyT: On a mid-range PIC, if `bitvar1` is bit 3 of address 0x12, and `bitvar2` is bit 6 of address 0x45, the instruction sequence `if (bitvar1) bitvar2=1` would be `btfsc 0x12,3 ; skip next instruction if bit 3 of address 0x12 is not set` followed by `bsf 0x45,6 ; set bit 6 of address 0x45`. Using bytes at those addresses, the shortest possible sequence would be: `movf 0x12,w ; load W with value and set Z flag iff zero`, `movlw 0x01 ; load W with 1 without affecting Z`, `btfss 3,2 ; Skip next instruction if Z flag set`, `movwf 0x45 ; Store W to address 0x45`. – supercat Jan 27 '14 at 17:14
  • @AndreyT: I'm not sure how many compilers would find that instruction sequence, since it requires moving the `movlw 1` before the conditional test. I suspect many would render it as `movf 0x12,w / btfsc 3,2 / goto skip / movlw 0x01 / movwf 0x45 / skip:`. Many embedded processors include instructions to directly test or set bits stored in memory, but do not include instructions to test whether memory bytes are zero, nor to directly set them to a non-zero value. – supercat Jan 27 '14 at 17:19
18

Section 6.5.8.6 of the C standard says:

Each of the operators < (less than), > (greater than), <= (less than or equal to), and >= (greater than or equal to) shall yield 1 if the specified relation is true and 0 if it is false.) The result has type int.

3

There seems to be no problem since the int to bool cast is done implicitly. This works in Microsoft Visual C++, GCC and Intel C++ compiler. No problem in either C or C++.

Alex James
  • 351
  • 1
  • 3
  • 11
  • 2
    "It works in some cases" isn't a good way to check for correctness, especially with unspecified versions of those tools. I prefer the approach in the other answers; they can't guarantee a particular implementation is correct, but they can guarantee what a correct implementation will do. – Matthew Read May 10 '12 at 21:15