Casting a logical boolean as an int?

Pages: 12
I have never run across a situation just like this one below and thought I would ask your thoughts on it.

Let's say I have a product that needs service after 500 hours at 100 RPM. I can dsiplay the remaining hours only as an integer and we only have integer math. Management wants it to display 500 for the first hour, not 499 after the first minute is ticked off. But after a few minutes fullHours will be 499 and partialHours will have some value. I have 3 ways to determine displayHours to suit management and I want to know if the first is ligit.

short fullHours = 500;
short partialHours = 0;
short displayedHours = 0;


// Method 1 - Is is Kosher to cast a boolean as an int? Is TRUE always a 1 or is that a bad assumption?

displayedHours = fullHours + (short) (partialHours != 0);


//Method 2 - Works but some have disdain for the ternary conditional

displayHours = fullHours + (partialHours ? 1 : 0);


//Method 3 - seems a bit pedantic

displayHours = fullHours;
if (partialHours != 0)
{
displayHours++;
}
Yes, you can cast from int to bool and back. If you cast from bool to int, the result will be 0 (false) or 1 (true). If you cast from int to bool, the result will be false (0) or true (any value other than zero).
It is completely legal, but I dislike implicit conversions between unrelated types. I would use method 3 or modified method 2: displayHours = fullHours + (partialHours > 0 ? 1 : 0);
Last edited on
Thanks. All good comments.

On the first method I was hoping my (short) cast would be seen as an effort to dis-implic - it. Your choice of modified method 2 makes sense, might take less cycles to check for greater than zero than checking for unequal to zero. It also better handles the case of partialHours going negative. Since you were not given the calculation code I think that is a wise choice.

Best Regards,

john
Out of curiousity, what is "partialHours"? Is this the minutes and seconds?

Andy

PS Also, do you have to use a signed short, or could you make it unsigned?

Last edited on
> might take less cycles to check for greater than zero than checking for unequal to zero.

The optimizer knows everything about what is going on; all these constructs would generate the same code.

The issue of style is all about people - how readable is the code for them?

I would just write displayedHours = fullHours + int( partialHours > 0 ) ; and expect a reasonably competent C++ programmer to have no trouble understanding it. In C++, bool is an integral type.

In my experience, unnecessary verbosity impairs readability; I'm not particularly fond of constructs like:
1
2
if( i > 25 ) return (true) ;
else return (false) ; 

partialHours would be better defined as partialRpmHourProduct. It will probably be a product of 3600 seconds and some TBD RPM which will become a constant such as FULL_RPM_SECOND_HOUR_PRODUCT. When the the partialRpmHourProduct bucket reaches that amount it will be emptied and fullHours will decrement by one. partialRpmHourProduct could be unsigned but the other two need to go negative to make the user feel like a slub for neglecting his product.

At some fixed TBD interval the RPM will be measured and multiplied by the seconds elapsed since the last check and added to the partial hour bucket. At another TBD interval the full and partial hours will be saved to flash, nvram, etc.

For some reason we are not allowed to use int but char, short, long, etc. I prefer u8, u16, etc. But if I were King ints would be allowed for general purposes, especially loop counters, etc as to me it seems best to use the native size for such things to avoid conversions, promotions, etc. But I know the native size int for this machine is the same as short so I use short or unsigned short as a default.

Once had to have a bitch-fit because I was 'wastefully' using ints instead of chars for some small function parameters. Then I produced the assembler output difference that showed wasteful extra code due to promotions, etc. Manager agreed that native size might be good sometimes.
> For some reason we are not allowed to use int but char, short, long, etc

Probably for portability reasons; on all the targeted platforms, char short and long have the same size (8, 16, 32 bits), but ints do not (16 bits on one, 32 bits on another).

> I prefer u8, u16, etc.

That, or std::uint16_t etc., would be a better way to specify fixed width integral types.


> But if I were King ints would be allowed for general purposes, especially loop counters, etc.

That would be the sane thing to do.
@MiiNiPaa
That should be (partialHours != 0 ? 1 : 0): negative numbers also evaluate to true.
I also use the (x ? 1 : 0) way.
It makes me feel safer, I don't need explicit int/short casts and I know it will be either 1 or 0.
> I don't need explicit int/short casts

No one needs explicit int/short casts; there is an implicit conversion from one integral type to another integral type. This would suffice:
displayedHours = fullHours + ( partialHours > 0 ) ;


> It makes me feel safer, I know it will be either 1 or 0.

The very basics:
A prvalue of an integer type can be converted to a prvalue of another integer type. ... If the source type is bool, the value false is converted to zero and the value true is converted to one.
@chrisname I assumed that partialHours was unsigned. There is little sense for it to be negative anyway.

I rarely use integer-boolean implicit conversion. Booleans represented as integral variable, but they does not have integral semantic and should not be threated as integers. They are different.
Boolean-integer conversion is source of many bugs and misunderstanding.
Up until C++11 no classes in standard library were convertible to bool because implicit bool-int conversion will lead to bunch of difficult to find runtime errors.
I would like an ability to explicitly forbid that conversions, as compiler switch or something else.
> I would like an ability to explicitly forbid that conversions, as compiler switch

No compiler would give you a switch of that kind; it cuts at the heart of C++.


> or something else.

Something else. Creating your own boolean type with the semantics that you want is trivial.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>

struct Java_boolean
{
    explicit constexpr Java_boolean( bool b = false ) : value(b) {}

    using Java_bool_t = void (Java_boolean::*)() const ;
    operator Java_bool_t() const { return value ? &Java_boolean::not_integral : nullptr ; }

    int to_int() const { return value ; }
    bool operator== ( Java_boolean that ) const { return value == that.value ; }
    bool operator!= ( Java_boolean that ) const { return value != that.value ; }
    Java_boolean operator! () const { return Java_boolean { !value } ; }

    private:
        bool value ;
        void not_integral() const {}

    template < typename STREAM > inline friend
    STREAM& operator << ( STREAM& stm, Java_boolean b )
    { return stm << "Java_" << ( b.value ? "true" : "false" ) ; }
};

constexpr Java_boolean Java_true { true } ;
constexpr Java_boolean Java_false { false } ;

int main()
{
    Java_boolean flag { Java_true } ;
    if( flag ) std::cout << "ok\n" ;
    if( flag == Java_true ) std::cout << "ok\n" ;
    std::cout << flag << '\n' ;

    int i = flag.to_int() ; // fine
    //int j = flag ; // error

    flag = Java_boolean(i) ; // fine
    // flag = i ; // error
}

http://ideone.com/yvCdRP
Creating your own boolean type
How to do that int x(0); if(-1 < x < 1) would give a compile-time error?
Or we don't have to convert to void pointers instead of bool?
Imagine somebody with basic knowledge of C++ studying your class: what purpose conversion to void pointer has?
Gladly in C++11 we have explicit keyword and we can avoid this with bools: http://ideone.com/i8lHfL

No compiler would give you a switch of that kind; it cuts at the heart of C++.
SO the switch which changes meaning and extending some keywords is fine. switch which add a bunch of non-standard extensions is fine too, special directives which changes parser behavior is fine too, but to disallow some conversions isn't possible?
For example it is possible to disallow use of some functions in GCC.
Last edited on
> How to do that int x(0); if(-1 < x < 1) would give a compile-time error?

Precisely the same way. If you want integers with your own semantics, create your own Java_integer type for which comparisons would return a Java_bool.


> Imagine somebody with basic knowledge of C++ studying your class: what purpose of converting to void pointer?

What is that 'what purpose of converting to void pointer? ' supposed to mean?

What is this 'what purpose of'? And what is this 'void pointer' that it is being converted to?
1
2
    using Java_bool_t = void (Java_boolean::*)() const ;
    operator Java_bool_t() const { return value ? &Java_boolean::not_integral : nullptr ;
Explain somebody studying C++ why you are returning pointers here, what they points to and how would we use values they points to.

If you want integers with your own semantics
Integers are fine here. They won't converted to unexpected types, they behave just as integers should.

What would prevent compiler vendor to create #pragma disallow_bool-int_conversion directive?

bool-int conversion is C leftovers and shouldn't be in C++. No high language have implicit bool-int conversions. Because booleans are not integers. To have bool-int conversion makes exactly that much sense as pointer-int (well, pointers represented as integers too).
> somebody studying C++

Somebody studying C++ (or somebody finding it hard to understand that bit) should stick to the bool and int types of C++.


> Integers are fine here.

Of course they are fine. bools are also fine, thank you very much. If you thought that they are fine here, why did you want to know how a compile time error could be generated for that fine construct?


> What would prevent compiler vendor to create #pragma disallow_bool-int_conversion directive?

Because it wouldn't be C++ any more. Because the vast majority of C++ programmers want that conversion. Because people who desperately want to prevent conversions between bool and int would be well advised to program in a language other than C++.

If you don't believe that, go make a feature request to the compiler vendors to add such a pragma. And submit a proposal to the standards committee about changing the semantics of integral conversions.


> bool-int conversion is C leftovers and shouldn't be in C++. No high language have implicit bool-int conversions. Because booleans are not integers.

So, go program in one of those languages if that suits you better. Instead of whining that the C++ community has a particular vision of the language, wants as much compatibility with C as possible. No one is begging you to program in C++. No one would try to prevent you from moving away from C++.
Somebody studying C++ (or somebody finding it hard to understand that bit) should stick to the bool and int types of C++.
Somebody with basic understanding of math should expect
1
2
int x =0; 
return  (-1 < x < 1);
to return true or disallow its use if such constructs isn't posible.
why did you want to know how a compile time error could be generated for that fine construct?
Because it is not working as anyone would expect.
Because it wouldn't be C++ any more
So #pragma omp ... is C++, function attributes is C++, non-standard language extension is C++, but if we give user ability to disallow one implicit conversion in one translation unit it immideatly stops being C++.
Because the vast majority of C++ programmers want that conversion.
I haven't seen any use of implicit bool→int conversion without documentation describing why this line works correctly and most of them were refactored into explicit check later. Talk about self descripting code.
wants as much compatibility with C as possible
So implicit conversion from non existing in C type is C compatibility? Why not provide conversion from list to int? It probably will make languages even more compatible.
I am talking only about bool→int conversion here. not int→bool or pointer→bool. Last ones does not cause so many errors and misunderstanding
C++ bool type and C bool typedef is not compatible and if we will write a program using C++ bool implicit conversions and bool semantic there would be high chance that it will not work in C — any language version before C99 (which is often incompatible with C++) or not using <stdbool.h> (because of legacy code reasons or others)
1
2
3
4
while(toProcess--) { //int→bool lesser of evils. At least it always behaves as you might expect.
    bool error - returnsErrorCode(); //We are interested only in fact that error happens, error codes are in range [-1; -10]
    errorCount += error;  //Neat use of implicit bool→int conversion, errorCount will always be non-negative.
} //Compiles in C just fine but will not work correctly 
Last edited on
> Somebody with basic understanding of math should expect
>
1
2
int x =0; 
> return  (-1 < x < 1);

> to return true or disallow its use

Anybody with basic understanding of programming would know that the int is not the integer in mathematics; for instance that can't hold any integer. That if x and y are two integers, while x+y is always well defined in mathematics, it is not so in programming.

Anybody with a basic understanding of C++ would realize that the < is a binary operator which results in a bool, that associativity is involved, that (int)(-1 < x < 1) would give the same results in both C and C++.


> I haven't seen any use of implicit bool→int conversion .... Talk about self descripting code.

Then you have seen very little code. Mny calls from within C++ to a C function taking a boolean value would involve an implicit conversion from bool to int.
char c = ... ; if( std::isupper(c) ) { /* ... */ } involves implicit conversions from char to int, and from int to bool

People who believe that to be self-describing, the code must be written as :
if( static_cast<bool>( std::isupper( static_cast<int>(c) ) ) { /* ... */ }
have my sympathies.


> C++ bool type and C bool typedef is not compatible ... blah blah

That is asinine. C compatibility does not mean that C++ code can be picked up and compiled with a C compiler.

It just means that
1
2
3
4
5
6
7
std::mutex make_win32_mutex( /* ... */ bool own = false, bool allow_inheritance = false )
{
    // ...
    ::SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), nullptr, allow_inheritance } ;
    auto m = ::CreateMutex( *sa, own, nullptr ) ;
    // ...
}

will work seamlessly. Not that this function can be compiled with a C compiler. But that one does not have to write (using some absurd notion of self-describing code)
1
2
3
4
5
6
7
8
9
std::mutex make_win32_mutex( /* ... */ bool own = false, bool allow_inheritance = false )
{
    // ...
    ::SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), static_cast<void*>(nullptr), 
                                 static_cast<int>(allow_inheritance) } ;
    auto m = ::CreateMutex( &sa, static_cast<int>(own), 
                             static_cast<void*>(nullptr) ) ;
    // ...
}:

Last edited on
JLBorges wrote:
involves implicit conversions from char to int, and from int to bool
MiiNiPaa wrote:
I am talking only about bool→int conversion here. not int→bool or pointer→bool. Last ones does not cause so many errors and misunderstanding
I still haven't seen where imlicit bool→int conversion would be useful.

Anybody with basic understanding of programming would know that the int is not the integer in mathematics
integers where 255 + 1 == 0 are defined in mathematics, anyone with math background will understand how they works. 2s complement was created and widely used because it allows operations with it to behave like algebraic ones.
In fact almost everything in computers is justified from mathematical sense.

In your earlier example you have used idiom, which has name "Safe bool idiom". Isn't this implies that bools in C++ are not safe? It was created as workaround to unsafe useless dangerous bollean => integer conversion. And on top of that it is slower than native types (creating pointer to non-static member function is not fastest operation). I'm glad that C++11 introduced explicit keyword with which we can finally create self-descriptive safe confersion which is intended to use in boolean context. Still it does not help other boolean problems.
Pages: 12