Casting to _Bool - c

Traditionally, Boolean values in C were represented with int or char. The new _Bool type makes intent clearer, but also has another interesting feature: it seems casting floating-point numbers to it, does not truncate toward zero, but compares with exact zero:
#include <stdio.h>
int main(int argc, char **argv) {
double a = 0.1;
int i = (int)a;
printf("%d\n", i);
_Bool b = (_Bool)a;
printf("%d\n", b);
return 0;
}
prints
0
1
So this is a semantic difference. And one I'm happy with; it duplicates the effect of using a floating-point number as a conditional.
Is this something that can be depended on across-the-board? Does the new C standard define the result of casting X to _Bool as identical to X ? 1 : 0 for all X for which that is a valid operation?

In the C Standard (6.3.1.2 Boolean type) there is written
1 When any scalar value is converted to _Bool, the result is 0 if the
value compares equal to 0; otherwise, the result is 1.
That is during conversion to the type _Bool the compiler does not try to represent the value (truncating toward zero or something else) of the operand of an expression with the casting operator as an integer. It only checks whether the value is equal or unequal to zero.
Actually this declaration
_Bool b = (_Bool)a;
is equivalent to
_Bool b = a;

It is entirely consistent, a non-zero value implicitly cast to _Bool is true. Since _Bool is a true Boolean type and not "faked", it can behave correctly. So:
_Bool b = (_Bool)a ;
is equivalent to:
_Bool b = (a == 0) ;
not:
_Bool b = ((int)a == 0) ;
In the end interpreting a float as Boolean is nonsense and ill-advised as is comparing it for equality to zero. If you want the semantic you expect, you must code it explicitly:
_Bool b = (_Bool)((int)a);
Semantically that is equivalent to :
_Bool b = (a < 1.0);
It is clearer and safer to use a Boolean expression than to force a value to Boolean with a cast.

Related

Does this equivalency return a bool or int?

I would like to write the following function to return whether a queue is empty or not:
#include <stdbool.h>
bool QueueIsEmpty(Queue *pq)
{
return (pq->items == 0)? true : false;
}
Would doing the following shorthand work for this?
bool QueueIsEmpty(Queue *pq)
{
return pq->items == 0;
}
In other words, does that return an int or a bool when doing the equivalency check? And if it returns a bool how does the compiler know to cast it to a bool, or is a bool just an int behind-the-scenes?
When trying it in Compiler Explorer, both seem to just do mov eax, 0 and produce identical assembly: https://godbolt.org/z/bY59r3.
Both are equivalent.
bool is considered an integer type which can only hold the values 0 and 1. true has a value of 1 while false has a value of 0.
The expression pq->items == 0 has type int and will evaluate to either 0 or 1. These are both valid values for bool so the value will be properly converted.
The value of comparison expression using any of ==, !=, <, >, <=, => will be a value 1 or 0 for true and false respectively, and, due to history, will be of type int.
_Bool type (for which bool is a macro alias defined in <stdbool.h>) can only store values 1 and 0. Additionally, when converting to _Bool, any nonzero value will be converted to 1. C11 6.3.1.2:
When any scalar value is converted to _Bool, the result is 0 if the value compares equal to 0; otherwise, the result is 1. [59]
[59] NaNs do not compare equal to 0 and thus convert to 1.
Therefore the following is valid:
bool QueueIsEmpty(Queue *pq)
{
return pq->items == 0;
}
The !x unary operator is exactly equivalent to x == 0 semantically and syntactically in all contexts, and therefore the former can be substituted everywhere in place of the latter, therefore the following is valid as well:
bool QueueIsEmpty(Queue *pq)
{
return !pq->items;
}
and the following is also valid for a function with opposite semantics:
bool QueueHasItems(Queue *pq)
{
return pq->items;
}
All of the functions have the same semantics regardless of the type of pq->items provided that the value of this expression has a scalar type (i.e. boolean, integer, pointer, real or complex floating point), or decays to one (i.e. if items is an array, then it will always be true...); and if it is not a scalar type then the code should fail to compile...
This compiles on x86-64 to
QueueHasItems:
cmp QWORD PTR [rdi], 0
setne al
ret
i.e. al is set as the result of zero/equality flag after cmp pq->items, 0.
pq->items == 0 results in an int with the value of 0 or 1.
bool QueueIsEmpty() returns a bool with the value of 0 or 1. With stdbool.h, a bool can only have the value of 0 or 1.
In C, there is no true bool type1. C uses the concept of falsey and truthy; if the expression evaluates to something non-zero, it can be used as truthy, otherwise, it is falsey.
Therefore in both cases you have, they will have the same effect.
You could also use the ! operator and do !pq->items;, which according to the logical operators documentation is the same as doing pq->items == 0
1 Since C99, C now supports boolean arithmetic using the _Bool type, and if you include stdbool.h, you can even get access to the macros true or false, which expand to 1 or 0, respectively.

What advantage does _Bool give?

If the _Bool type acts like an integer and doesn't enforce that a value is true/false or 1/0, for example:
_Bool bools[] = {0,3,'c',0x17};
printf("%d", bools[2]);
> 1
What is the advantage of having that there? Is it just a simple way to coerce things to see how they would evaluate for 'truth-ness', for example:
printf("%d\n", (_Bool) 3);
> 1
Or how is this helpful or useful in the C language?
What advantage does _Bool give?
The value of a _Bool is either 0 or 1. Nothing else, unlike an int.
Conversion to a _Bool always converts non-zero to 1 and only 0 to 0.
When any scalar value is converted to _Bool, the result is 0 if the value compares equal to 0; otherwise, the result is 1.
Examples:
#include <math.h>
#include <stdlib.h>
_Bool all_false[] = { 0, 0.0, -0.0, NULL };
_Bool all_true[] = { 13, 0.1, 42.0, "Hello", NAN };
Notice the difference of conversion/casting to int vs; _Bool: (int) 0.1 --> 0, yet (_Bool) 0.1 --> 1.
Notice the difference of conversion/casting to unsigned vs; _Bool: (unsigned) 0x100000000 --> 0, yet (_Bool) 0x100000000 --> 1.
_Bool adds clarity to boolean operations.
_Bool is a distinctive type from int, char, etc. when used with _Generic.
Prior to C99, C lacked _Bool. Much early code formed their own types bool, Bool, boolean, bool8, bool_t, .... Creating a new type _Bool brought uniformity to this common, yet non-uniform practice. <stdbool.h> is available to use bool, true, false. This allows older code, which does not include <stdbool.h> to not break, yet newer code to use cleaner names.
OP's example with "doesn't enforce that a value is true/false or 1/0" does enforce that bools[2] had a value of 1. It did not enforce that the initializer of 'c', an int, had to be in the range of [0...1] nor of type _Bool, much like int x = 12.345; is allowed. In both cases, a conversion occurred. Although the 2nd often generates a warning.
The advantage is legibility, nothing more. For example:
bool rb() {
if (cond && f(y)) {
return true;
}
return false;
}
Versus:
int rb() {
if (cond && f(y)) {
return 1;
}
return 0;
}
There's really no other benefit to it. For those that are used to working in C code without bool, it's largely cosmetic, but for those used to C++ and its bool it may make coding feel more consistent.
As always, an easy way to "cast to a boolean value" is just double negation, like:
!!3
Where that will reduce it to a 0 or 1 value.
Consider this:
(bool) 0.5 -> 1
( int) 0.5 -> 0
As you can see, _Bool does not act like an integer.

C Compare enumerate with invalid value

I would like try to understand how is working the compilator when we compare an enumerate with invalid value, and what the program is doing during execution.
I found strange source code during my work, and did not understand the behaviour of the program, which was not giving me the expected result.
I wrote the following little program to summarize my problem.
I create an enum E_Number and I instanciate a variable a, with the value -1.
Then I perform comparison on a to check if it belongs to the range of the enum.
(I know, this is really strange, but this is exactly what i found in source code !)
I expected the result tells me Not in range because of the fail of the first condition (a >= FIRST_ENUM).
But it was the fail of the second condition (a < NB_MAX_NUMBER) which gave me the right result (see the printf())...
If I cast a in (int) in the if conditions, I get excepted results.
So what is happening during the execution ? Is the program considering -1 as an other possible enum value which will be positionned after NB_MAX_NUMBER ? What is the rule for > and < operator on enum ?
#include <stdio.h>
#define FIRST_ENUM 0
typedef enum{
NUM_1 = FIRST_ENUM,
NUM_2,
NUM_3,
NB_MAX_NUMBER
}E_Number;
int main()
{
E_Number a = -1;
if ((a >= FIRST_ENUM) && (a < NB_MAX_NUMBER))
{
printf("In Range\n");
}
else
{
printf("Not in Range\n");
}
printf("1st condition = %s\n", (a >= FIRST_ENUM)?"TRUE":"FALSE");
printf("2nd condition = %s\n", (a < NB_MAX_NUMBER)?"TRUE":"FALSE");
return 0;
}
gcc program.c
.\a.exe
Not in Range
1st condition = TRUE
2nd condition = FALSE
I am working with MINGW compilator ( gcc (x86_64-win32-seh-rev1, Built by MinGW-W64 project) 4.9.2 )
In your case the compiler consider E_Number as unsigned int because all the legal values are unsigned, so -1 is considered to be ~0u which is >= FIRST_ENUM and < NB_MAX_NUMBER
I have the same behavior with gcc version 6.3.0 20170516 (Raspbian 6.3.0-18+rpi1+deb9u1)
pi#raspberrypi:~ $ ./a.out
Not in Range
1st condition = TRUE
2nd condition = FALSE
But, if I change your definitions like that :
#include <stdio.h>
#define FIRST_ENUM -1
typedef enum{
NUM_1 = FIRST_ENUM,
NUM_2,
NUM_3,
NB_MAX_NUMBER
}E_Number;
int main()
{
E_Number a = -2;
if ((a >= FIRST_ENUM) && (a < NB_MAX_NUMBER))
{
printf("In Range\n");
}
else
{
printf("Not in Range\n");
}
printf("1st condition = %s\n", (a >= FIRST_ENUM)?"TRUE":"FALSE");
printf("2nd condition = %s\n", (a < NB_MAX_NUMBER)?"TRUE":"FALSE");
return 0;
}
the behavior change and the enum is considered to be an int and I have :
pi#raspberrypi:~ $ ./a.out
Not in Range
1st condition = FALSE
2nd condition = TRUE
Enumarator constants are of type int. The enumerator type is an unspecified integer type capable of representing all the enumerator constants.
6.7.2.2p4:
Each enumerated type shall be compatible with char, a signed integer
type, or an unsigned integer type. The choice of type is
implementation-defined,128) but shall be capable of representing the
values of all the members of the enumeration. The enumerated type is
incomplete until immediately after the } that terminates the list of
enumerator declarations, and complete thereafter.
Since you haven't enumerated any negative values, that type may well be an unsigned type. If it is, then (E_Number)some_integer will always be greater than or equal to zero (0==FIRST_ENUM).
If you expand the enum list to:
typedef enum{
NUM_NOPE=-1,
NUM_1 = FIRST_ENUM,
NUM_2,
NUM_3,
NB_MAX_NUMBER
}E_Number;
you'll force the compiler to use a signed type and the results will reverse.
Quote from ISO/IEC 9899:1999, 6.7.2.2p3
Each enumerated type shall be compatible with char, a signed integer
type, or an unsigned integer type. The choice of type is
implementation-defined, 108) but shall be capable of representing the
values of all the members of the enumeration.
So, when you declare an enumeration, you cannot be sure a priori about what kind of data will the implementation of C choose to store that variable. Optimisation reasons, the compiler may not choose an integer type on 4 bytes if you store enumeration constants between [-128, +127]. The implementation may choose char to store an enumerated variable, but you cannot be sure. Any integer data type can be chosen as time as it can store all possible values.

A Macro using sizeof(arrays) is not giving the expected output

#include <stdio.h>
int arr[] = {1, 2,3,4,5};
#define TOT (sizeof(arr)/sizeof(arr[0]))
int main()
{
int d = -1, x = 0;
if(d<= TOT){
x = arr[4];
printf("%d", TOT);
}
printf("%d", TOT);
}
TOT has the value 5 but the if condition is failing..why is that?
Because there are "the usual arithmetic conversions" at work for the if.
The sizeof operator returns an unsigned type ... and d is converted to unsigned making it greater than the number of elements in arr.
Try
#define TOT (int)(sizeof(arr)/sizeof(arr[0]))
or
if(d<= (int)TOT){
That's because sizeof returns an unsigned number, while d is signed. When d implicitly converted to a singed number, and then it is much much larger than TOT.
You should get a warning about comparison of signed-unsigned comparison from the compiler.
Your expression for TOT is an unsigned value because the sizeof() operator always returns unsigned (positive) values.
When you compare the signed variable d with it, d gets automatically converted to a very large unsigned value, and hence becomes larger than TOT.
return type of sizeof is unsigned integer ....that is why if is failing ...because "d" which is treated as signed by the compiler is greater than TOT

Two Equal Signs in One Line?

Could someone please explain what this does and how it is legal C code? I found this line in this code: http://code.google.com/p/compression-code/downloads/list, which is a C implementation of the Vitter algorithm for Adaptive Huffman Coding
ArcChar = ArcBit = 0;
From the function:
void arc_put1 (unsigned bit)
{
ArcChar <<= 1;
if( bit )
ArcChar |= 1;
if( ++ArcBit < 8 )
return;
putc (ArcChar, Out);
ArcChar = ArcBit = 0;
}
ArcChar is an int and ArcBit is an unsigned char
The value of the expression (a = b) is the value of b, so you can chain them this way. They are also right-associative, so it all works out.
Essentially
ArcChar = ArcBit = 0;
is (approximately1) the same as
ArcBit = 0;
ArcChar = 0;
since the value of the first assigment is the assigned value, thus 0.
Regarding the types, even though ArcBit is an unsigned char the result of the assignment will get widened to int.
1   It's not exactly the same, though, as R.. points out in a comment below.
ArcChar = ArcBit = 0;
The assignment is left-associative, so it's equivalent to:
ArcChar = (ArcBit = 0);
The result of ArcBit = 0 is the newly-assined value, that is - 0, so it makes sense to assign that 0 to ArcChar
It sets both variables to zero.
int i, j;
i = j = 0;
The same as writing
int i, j;
j = 0;
i = j;
or writing
int i, j;
i = 0;
j = 0;
That is just chaining of the assignment operator. The standard says in 6.5.16 Assignment operators:
An assignment operator shall have a modifiable lvalue as its left operand.
An assignment operator stores a value in the object designated by the left operand. An
assignment expression has the value of the left operand after the assignment, but is not an
lvalue. The type of an assignment expression is the type of the left operand unless the
left operand has qualified type, in which case it is the unqualified version of the type of
the left operand. The side effect of updating the stored value of the left operand shall
occur between the previous and the next sequence point.
So you may do something like:
a=b=2; // ok
But not this:
a=2=b; // error
An assignment operation (a = b) itself returns an rvalue, which can be further assigned to another lvalue; c = (a = b). In the end, both a and c will have the value of b.
It assigns ArcBit to 0, then assigns ArcChar to the value of the expression ArcBit = 0 (ie. 0)
In some languages, assignments are statements: they cause some action to take place, but they don't have a value themselves. For example, in Python1 it's forbidden to write
x = (y = 10) + 5
because the assignment y = 10 can't be used where a value is expected.
However, C is one of many languages where assignments are expressions: they produce a value, as well as any other effects they might have. Their value is the value that is being assigned. The above line of code would be legal in C.
The use of two equals signs on one line is interpreted like this:
ArcChar = (ArcBit = 0);
That is: ArcChar is beging assigned the value of ArcBit = 0, which is 0, so both variables end up being 0.
1 x = y = 0 is actually legal in Python, but it's considered a special-case of the assignment statement, and trying to do anything more complicated with assignments will fail.
Assignment in C is an expression, not statement. Also you can freely assign values of different size (unsigned char to int and vice versa). Welcome to C programming language :)
You can do this:
http://en.wikibooks.org/wiki/C_Programming/Variables
Moreover,
[a int] = 0; is possible.
[a char] = 0; is possible too.
arcbit and arcchar equals 0.
As Hasturkun said, this is due to operator associativity order
C Operator Precedence and Associativity

Resources