Do negative numbers return false in C/C++?

69,400

Solution 1

All non-zero values will be converted to true, and zero values to false. With negative numbers being non-zero, they are converted to true.

Quoting from the C++11 standard (emphasis mine):

4.12 Boolean conversions [conv.bool]

1 A prvalue of arithmetic, unscoped enumeration, pointer, or pointer to member type can be converted to a prvalue of type bool. A zero value, null pointer value, or null member pointer value is converted to false; any other value is converted to true. A prvalue of type std::nullptr_t can be converted to a prvalue of type bool; the resulting value is false.


Are they always true/false regardless of compilers?

You will only get the above guarantee when your compiler is standards-compliant, or at least, complies with this specific part of the standard. In practice, all compilers have this standard behavior, so there isn't much to worry about.

Solution 2

You can test it yourself by compiling this:

#include <stdio.h>

int main(int argc, char** argv) {
    if (-1) {
        printf("-1 is true\n");
    } else {
        printf("-1 is false\n");
    }
    return 0;
}

Results:

$ gcc -Wall -pedantic test.c -o test-c
$ g++ -Wall -pedantic test.c -o test-cpp
$ ./test-c
-1 is true
$ ./test-cpp
-1 is true

Of course, to answer the second part of your question, "Are they always true/false regardless of compilers?", the only way to be completely sure is to look at the spec. In general though, compilers will warn you if you do something dangerous, and you can see from the output above, that even with "pedantic" warnings, gcc considers this code to be perfectly fine.

Solution 3

Short answer: Negative values, and any non-zero values in general, are treated as true when used as conditions.

For C, there are a number of contexts in which an expression is treated as a condition. Conditions are not necessarily of type bool or _Bool; that type was only added to the language by the 1999 standard.

The most obvious of these contexts is the expression in an if statement, but there are other examples: while, do-while, the second expression in a for header, the first operand of the ?: conditional operator, and the operand(s) of the !, &&, and || operators. (I think that's an exhaustive list, but I'm not certain.)

Here's what the C standard says about the behavior of the if statement (the "two forms" refer to if with and without an else clause):

In both forms, the first substatement is executed if the expression compares unequal to 0.

Which means that this:

if (foo) ...

is equivalent to this:

if ((foo) != 0) ...

(adding extra parentheses to avoid any operator precedence issues). The meaning is clear if foo is of type int. If foo is of some floating-point type, 0 is converted to the same type (which can cause some subtleties if the value happens to be a negative zero or a NaN). And if foo is a pointer, 0 is treated as a null pointer constant; if (ptr) is equivalent to if (ptr != NULL) (assuming the definition of NULL is visible).

For C++, the rules are stated a bit differently, but the effect is the same. The condition in a C++ if statement is converted to type bool (unlike in C, the type bool has been built into C++ since its early history). The conversion of a value of any scalar type to bool is defined by the C++ standard as:

A zero value, null pointer value, or null member pointer value is converted to false; any other value is converted to true. A prvalue of type std::nullptr_t can be converted to a prvalue of type bool; the resulting value is false.

So in both C and C++, any scalar (i.e., integer, floating-point, or pointer) value can be used as a condition, and the condition is false if the scalar is equal to zero, and true if it's not equal to zero. C defines this as an inequality comparison to 0; C++ defines it as a conversion to the bool -- but the result is the same.

This is getting a bit off the topic of the question, but I'll mention that it's important to note that a value that is treated as a true condition is not necessarily equal to true. true (which is 1 in C if you have #include <stdbool.h>, and a unique value of type bool in C++) is just one of many values that possess "truthiness" when used in a condition. Which is why you should almost never write:

if (cond == true) ...

in either C or C++ (unless you really need to compare it to that one value); just write:

if (cond) ...

A C++ example:

#include <iostream>
int main() {
    int n = 2;
    if (n)         std::cout << "n has truthiness\n";
    else           std::cout << "n does not have truthiness\n";
    if (n == true) std::cout << "n == true\n";
    else           std::cout << "n != true\n";
}

The output is:

n has truthiness
n != true

Solution 4

Anything that is not 0 will be converted to true(1 in the case of C) a zero value will be converted to false(0 in the case of C). With respect to C if we look at the C99 draft standard section 6.3.1.2 Boolean type paragraph 1 says:

When any scalar value is converted to _Bool, the result is 0 if the value compares equal to 0; otherwise, the result is 1.

For completeness sake if we look at section 7.16 Boolean type and values paragraph 2 says:

The macro 

 bool

expands to _Bool.

with respect to C++ the draft C++ standard in section 4.12 Boolean conversions paragraph 1 says(emphasis mine):

A prvalue of arithmetic, unscoped enumeration, pointer, or pointer to member type can be converted to a prvalue of type bool. A zero value, null pointer value, or null member pointer value is converted to false; any other value is converted to true.[...]

This should hold regardless of which compiler you use.

Share:
69,400
Admin
Author by

Admin

Updated on July 08, 2022

Comments

  • Admin
    Admin almost 2 years

    When evaluating integers as booleans in C/C++, are negative numbers true or false? Are they always true/false regardless of compilers?

  • rici
    rici over 10 years
    In standard C (99 or 11, at least), LONG_MIN must be less than or equal to -2147483647, and decimal integer constants are given the first type of int, long int, long long int which can represent the number. Consequently, -65536 will be either int or long int, and in any case negative. So regardless of the bitness of the machine, if (-65536) do_it(); will always do_it(). Had you assigned -65536 (or, for that matter, 65536) to uint16_t a, then if (a) do_it(); probably wouldn't do_it(), but a probably wouldn't be negative (UB, though).
  • DanielV
    DanielV over 10 years
    On a 16 bit microcontroller, int and long int are probably both going to be 16 bits, in which case -65536 will be stored as the literal zero, maybe with a compiler warning, but it will still be zero.
  • rici
    rici over 10 years
    @danielV: if long int is 16 bits, then what you have is not a compliant C compiler, and if the C compiler is not compliant,then it might do anything, but it's no longer C. A compliant compiler would have to provife software 32-bit arithmetic. It's not hard to do. gcc implements 64-bit arithmetic on machines with only 32 bit ALUs. The standard is very clear about the minimum size of long.
  • Shafik Yaghmour
    Shafik Yaghmour over 10 years
    Being nit-picky but an example run on one or even several compilers does not prove this works or should work across all of them, i.e. that it is not implementation dependent.
  • Brendan Long
    Brendan Long over 10 years
    @ShafikYaghmour That's true. I updated the answer to give some more detail, and also add -Wall -pedantic, to show that gcc doesn't see anything wrong with this. I created this answer after the spec ones, mainly to show that the first part of the question is easily testable.
  • phuclv
    phuclv almost 10 years
    @DanielV according to the standard long must be at least 32 bits
  • Keith Thompson
    Keith Thompson over 4 years
    Note that the question (perhaps not entirely appropriately) asks about both C and C++. The result is the same in both, but the rules are stated differently. See my answer for the gory details.