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

2
  • Because of my low repotation, I couldn't have used boostlexical_cast as tag! Commented Jun 10, 2019 at 13:35
  • Possible duplicate of How can bool variable be not equal to both True and False?. So basically problem is undefined behavior when you override bool value Commented Jun 10, 2019 at 13:55

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

3 Comments

You are correct. Fiddling with the internal bits of a thing like this is not permitted.
C++11 used to say this explicitly, although I can't find that note in more recent versions (but it's still true)
Okay it was removed in this edit 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!
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.

4 Comments

"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 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?
Indeed they do. The purpose of my comment is to empower you to remove your "I'd have to double-check" part.
"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)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.