Pointers and Booleans

Started by
11 comments, last by TheUnbeliever 12 years, 1 month ago
How come it's perfectly fine to do:

[source]
int* ptr = 0;
if (ptr) {}
[/source]


But I get "Forcing value to bool (performance warning)" when I do:

[source]
int* ptr = 0;

bool isValid() {
return ptr;
}

if (isValid()) {}
[/source]


I don't understand how these are any different.
Advertisement
They are different in that if(ptr) is technically compiled into an integer/pointer comparison. There should be a special instruction for comparing whether an integer or pointer is 0 in x86 instructions set.

When returning a boolean from pointer it is first converted boolean and then a boolean comparison instruction is used. Therefore it is a bit slower. Generally the difference in speed is so little that you can just safely do this to avoid warnings:

int* ptr=0;
bool isValid() {
return (bool)ptr;
}


At least that's the general idea.

They are different in that if(ptr) is technically compiled into an integer/pointer comparison. There should be a special instruction for comparing whether an integer or pointer is 0 in x86 instructions set.

When returning a boolean from pointer it is first converted boolean and then a boolean comparison instruction is used. Therefore it is a bit slower. Generally the difference in speed is so little that you can just safely do this to avoid warnings:

int* ptr=0;
bool isValid()
{
return (bool)ptr;
}


At least that's the general idea.


It's nicer and easier to read to write that as, this makes the intent of the code clear whereas that cast just looks nasty, also the compiler can optimize that call away in this case.

int* ptr=0;
bool isValid()
{
return ptr != 0;
}

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

Completely agreed, ptr!=0 is much better. I wasn't thinking further from avoiding the warning.
More to the point, a bool has to have the value 0 or 1. A pointer can have any value. Thus converting a pointer to a bool requires checking if it's non-null and returning a 1 if that's the case. The if doesn't need to actually convert to a 1, it can just check if it's non-null.
More to the point, a bool has to have the value 0 or 1.[/quote]
Actually, a boolean can be represented by any word size (assumed 8 bytes since that's the smallest addressable memory size on current hardware), and by convention we define FALSE to be the value zero and TRUE to be any other value. (not that this invalidates your point, just some trivia).

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”


More to the point, a bool has to have the value 0 or 1.

Actually, a boolean can be represented by any word size (assumed 8 bytes since that's the smallest addressable memory size on current hardware), and by convention we define FALSE to be the value zero and TRUE to be any other value. (not that this invalidates your point, just some trivia).
[/quote]You're talking about C.
In C++, which would be the language used here, there is an actual bool as a built-in type, where true is implicitly convertible to 1. Any nonzero is still treated as true of course.

Also, rather than ptr != 0, the preferabe way to do it is ptr != NULL, or if using C++0x, then ptr != nullptr
"In order to understand recursion, you must first understand recursion."
My website dedicated to sorting algorithms

Actually, a boolean can be represented by any word size (assumed 8 bytes since that's the smallest addressable memory size on current hardware)...
[/quote]
Modern processors can still address individual bytes. The caching infrastructure might have a minimum threshold of data, but that doesn't mean that this is the minimum size of any unit of data.

Boolean values are typically 1 byte long on consumer hardware. Common exceptions include when they force structure padding or end up on the stack.


...and by convention we define FALSE to be the value zero and TRUE to be any other value.
[/quote]
For conditional expressions, sure. For boolean values, there are other considerations.

I believe the reason for forcing boolean expressions to true or false (rather than non-zero and 0) is to allow explicit boolean comparisons to be more reliable:

bool a = foo.isValid();
if(a == true) {
// "Unlikely" to get here without forcing boolean to true/false
}

bool b = /* ... */;
if(a == b) {
// Will we get here?
}

Sure, the above code could be written as:


bool a = foo.isValid();
if(a) {
// Will surely get here
}

bool b = /* ... */;
if((a && b) || !(a || b)) {
// We'll get here, but at what cost!!!11!1
}

I believe the first case represents an improvement over the explicit comparison, but the second case is considerably harder to comprehend (the intent is not clear).


(not that this invalidates your point, just some trivia).
[/quote]
I wouldn't recommend playing the C++ trivia game with SiCrane.


...and by convention we define FALSE to be the value zero and TRUE to be any other value.

For conditional expressions, sure. For boolean values, there are other considerations.

I believe the reason for forcing boolean expressions to true or false (rather than non-zero and 0) is to allow explicit boolean comparisons to be more reliable:

bool a = foo.isValid();
if(a == true) {
// "Unlikely" to get here without forcing boolean to true/false
}

bool b = /* ... */;
if(a == b) {
// Will we get here?
}

Sure, the above code could be written as:


bool a = foo.isValid();
if(a) {
// Will surely get here
}

bool b = /* ... */;
if((a && b) || !(a || b)) {
// We'll get here, but at what cost!!!11!1
}

I believe the first case represents an improvement over the explicit comparison, but the second case is considerably harder to comprehend (the intent is not clear).
[/quote]
If true was defined on a language level or by the compiler to be any non-zero value stored in the physical bool-variable in memory, then it would also be the language's or compiler's responsibility to perform the correct comparison. Thus, if true is a non-zero value and two trues are required to compare equal, then it would be the compiler's responsibility,not the user's, to implement the == operator correctly.

Compare to how how IEEE 754 floating point values work. There are positive and negative zeros which have different bit patterns but a normal equality comparison is enough to compare the positive and negative zeros as equal. Similarly, NaN's are/can be bit-wise identical in memory, yet equality comparison has to be false. The specification says all representations of zero are equal, and all NaNs are different, so the hardware has to ensure that equality is implemented correctly

If bools were allowed varying bit patters on the hardware level to represent the same logical value values on the language level, then the same would apply to them. It would not be your responsibility to compare them correctly, and you would never have to write more than a single comparison to see if a value is true or if two trues are equal.

I'm not sure if the language specification even allows for this in the first place though, so it may just be of academic interest. But given how little details are specified sometimes and how much is open for implementation details, who knows...
I'm not sure if the language specification even allows for this in the first place though, so it may just be of academic interest. But given how little details are specified sometimes and how much is open for implementation details, who knows...[/quote]
Well if the language doesn't support casting a byte/int/etc.. to a bool, you can always go ghetto:
1. allocate a byte (or whatever the size of a boolean in memory is on the target hardware).
2. write the integer "42" in it.
3. copy that memory into a boolean variable of your choice.
4. blink.png

When I was still learning programming a while ago I always wondered what would happen if I put something else than a true or a false into a boolean. Now I know. It's kind of fun messing around with some aspects of a language which aren't well-documented. To me anyway.

FWIW I did a quick test in C, then in Delphi. Turns out they don't handle booleans the same. C appears to only check the least significant bit for equality, whereas Delphi performs a complete byte comparison. Thus doing that hack in C will have no effect since it only ever looks at one bit, whereas it will utterly destroy program logic in Delphi. Check it out:


#include <stdio.h>
#include <stdbool.h>

int main( int argc, const char* argv[] )
{
bool a, b;
char v;

a = false;
b = false;

v = 43;
memcpy(&a, &v, 1);

v = 45;
memcpy(&b, &v, 1);

if (a == true)
{
printf("A = TRUE.\n");
}
else
{
printf("A = FALSE.\n");
}

if (b == true)
{
printf("B = TRUE.\n");
}
else
{
printf("B = FALSE.\n");
}
}

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

This topic is closed to new replies.

Advertisement