7

Output of boost::lexical_cast with a bool variable as input is expected to be a 0 or 1 value. But I get different value instead.

It's not something which happen normally. Let's take a look at example code I've wrote:

#include <string>

#include <boost/lexical_cast.hpp>

int main()
{
    bool alfa = true;    // Doesn't metter whether alfa is initialized at definition or not 
    char beta = 71;    // An integer value. Different values don't make any differences.
    memcpy(&alfa, &beta, sizeof(alfa));
    printf("%s\n", boost::lexical_cast<std::string>(alfa).c_str());
}

From this code, I've got "w" (ASCII code of w is 71) as output! But I expected it to be a 0 or 1 value.

The problem is just the value that bool variable will cast into. The bool variable in the given example is already considered true. What causes problem is imagine I want to convert back the converted value. That's where it throws exception because for example "w" character can't be converted to bool. But if the output was 0 or 1, re-conversion would be possible.

std::string converted_value = boost::lexical_cast<std::string>(alfa);
bool reconverted_value = boost::lexical_cast<bool>(converted_value );   // In this line, boost::bad_lexical_cast will be thrown

I was wondering whether the output is right or this is a bug in boost::lexical_cast?

Also when I was trying to do the same thing and cast the variable to int, I faced boost::bad_lexical_cast exception.

My boost version: 1.58

Live sample

rezaebrh
  • 424
  • 2
  • 6
  • 19
  • Because of my low repotation, I couldn't have used `boostlexical_cast` as tag! – rezaebrh Jun 10 '19 at 13:35
  • Possible duplicate of [How can bool variable be not equal to both True and False?](https://stackoverflow.com/questions/35075563/how-can-bool-variable-be-not-equal-to-both-true-and-false). So basically problem is undefined behavior when you override `bool` value – Marek R Jun 10 '19 at 13:55

2 Answers2

8

The C++ standard does not specify how a Boolean is stored in memory, only that there are two possible values: true and false. Now, on your machine, I presume these are stored, respectively, as 1 and 0. The compiler is allowed to make assumptions, and in particular it's allowed to assume that these are going to be the only two values stored in a Boolean.

Thus, when boost::lexical_cast sees a Boolean, it runs code that probably looks something like this (after optimization)

// Gross oversimplification
std::string lexical_cast(bool value) {
  char res = '0' + (int)value;
  return std::string(1, res);
}

If value is 0 or 1, this works fine and does what you want. However, you put a 71 into it. So we add the ASCII code of '0' (48) to 71 and get 119, the ASCII code of 'w'.

Now, I'm not a C++ standard expert, but I would guess that storing a non-standard value into a Boolean with memcpy is undefined behavior. At the very least, your code is non-portable. Perhaps someone more versed in the standard can fill in the holes in my knowledge as far as that's concerned.

Silvio Mayolo
  • 62,821
  • 6
  • 74
  • 116
  • You are correct. Fiddling with the internal bits of a thing like this is not permitted. – Lightness Races in Orbit Jun 10 '19 at 14:30
  • 1
    [C++11 used to say this explicitly](https://stackoverflow.com/a/56369368/560648), although I can't find that note in more recent versions (but it's still true) – Lightness Races in Orbit Jun 10 '19 at 14:33
  • 1
    Okay it was removed in [this edit](https://github.com/cplusplus/draft/commit/a5603f0cf1b35097a9892d9627eb03dc5cc3e154#diff-a7cb4634eeb2e4ce984d41aaa9a70ef4) for an editorial reason (so it'll be gone in C++20 but the footnote is still there in C++17). Again, the basic fact is still true though! – Lightness Races in Orbit Jun 10 '19 at 14:40
1

You broke the rules. What did you expect, that C++ would add useless code to your program to catch rule-breakers?

Boolean variables can only be 0 or 1, false or true. And they are, if you assign to them properly, according to the rules.

If you memcpy them or reinterpret_cast then the underlying implementation shows through. A bool is a memory byte. If it somehow gets set to something other than 0 or 1 then there it is.

I'd have to double-check but I'm not even sure you are guaranteed that a bool is one byte. I think you can take a pointer to it. But if the hardware had some way to create a pointer to one bit, you could be quite surprised at what C++ did with that.

Zan Lynx
  • 53,022
  • 10
  • 79
  • 131
  • "I'd have to double-check but I'm not even sure you are guaranteed that a bool is one byte" sizeof(bool) must be *at least* 1. It being the same size as int is common. – Bathsheba Jun 10 '19 at 13:51
  • @Bathsheba When people implement C or C++ on strange hardware they have to make compromises. On a machine with limited RAM and 32-bit minimum size "bytes" are you going to waste 31 bits to store 1 bit, or take a few compromises? – Zan Lynx Jun 10 '19 at 13:53
  • Indeed they do. The purpose of my comment is to empower you to remove your "I'd have to double-check" part. – Bathsheba Jun 10 '19 at 13:55
  • _"Boolean variables can only be 0 or 1, false or true"_. No. They can only be false or true. Period. They can never be 0 or 1. They are not numbers. They are booleans. They will _convert to_ 0 or 1 happily. Big difference! (And the crux of this question) – Lightness Races in Orbit Jun 10 '19 at 14:32