Compare two bools with different int value - c

#include <stdbool.h>
#include <stdio.h>
int main ()
{
bool a, b;
a = 1;
b = 4;
if (a == b)
printf ("They are equal\n");
else
printf ("They are different\n");
}
This code prints They are equal
How can this happen? Are the variables a and b being filled with the value 0x1 in the assignment regardless of what I assign to them? Or maybe is it the == that has been hacked to handle bools?
Is this behaviour portable accross C Standard Library implementations and compilers?
What was the correct way of logically comparing two bool/int before the introduction of stdbool.h ?

How can this happen?
Both variables are 1, so they are equal.
Are the variables a and b being filled with the value 0x1 in the assignment regardless of what I assign to them?
Well, not regardless. Any non-zero value is converted to 1 and assigned to bool. A zero value will fill them with... 0.
Or maybe is it the == that has been hacked to handle bools?
No.
It's that bool is a macro that expands to _Bool and that _Bool variables have special semantics when assigning a value to it.
Is this behaviour portable accross C Standard Library implementations and compilers?
Yes.
What was the correct way of logically comparing two bools before the introduction of stdbool.h ?
When bool is not an _Bool, but like an int, you can convert the values on assignment or comparison to 0 or 1 with double logical NOT:
if (!!a == !!b)

C11, 6.3.1.2 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.
When you assign 4 to b, it's simply assigned to 1. So yes, this behaviour is guaranteed by the C standard.

Related

Return True or 1?

As I know, Boolean is basically a char datatype, one byte, 0x00 or 0x01. Also, as I know, Integer is multiple bytes.
bool foo () {
return true; // I guess is 0x01 one byte
return 1; // I guess is 0x00000001 four bytes (depend on the platform)
}
Why do both returns work?
Here is what the C 2017 standard says about bool (aka _Bool) so "basically a char" is not correct:
An object declared as type _Bool is large enough to store the values 0 and 1. (6.2.5)
return 1 works due to automatic type conversion:
When any scalar value is converted to _Bool , the result is 0 if the value compares equal to 0; otherwise, the result is 1 (6.3.1.2)
There is no "best practice" as far as I know. I did not see it covered in MISRA C for instance. It may be covered in coding guidelines for your project(s) though. I use 0 and 1 as I favor compact code.
As others have explained, the size of a bool is not specified by the standard, so a compiler implementation is free to use any size as long as it can hold the values 0 and 1.
My clear recommendation is to use a bool type if the information is true/false by nature. Using an integer as boolean can lead to subtle errors. Consider the following (inspired by a real-life bug):
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
uint8_t isThisTrueInt(void)
{
int x = 256;
return x;
}
bool isThisTrueBool(void)
{
int x = 256;
return x;
}
int main(void)
{
printf("%s\n", (isThisTrueInt())?"true":"false");
printf("%s\n", (isThisTrueBool())?"true":"false");
return 0;
}
The result is:
false
true
The point being that converting 256 to an 8-bit integer truncates to 0, i.e. "false" while conversion to bool will give "true" for any non-zero integer.
As I know, Boolean is basically a char datatype, one byte, 0x00 or 0x01
That is not the case, the size of bool type is implementation-defined and is not specified in the C standard, it is usually defined in stdbool.h as of C99 and is normally something like:
#define bool _Bool
#define false 0
#define true 1
Before that it wasn't even a mandated type. You can say that in some implementations it's equivalent to a single byte, but not always, the specification only requires that bool is large enough to hold the values 0 or 1 and this ranges from 1 bit to the largest type possible, natively long long.
What's the best practice to follow?
This is an opinion based question, still, thinking about it, I would advise to use true/false because it's a pattern used in pretty much all the languages and it'll surely be easier to understand, I must admit I'm not the best follower of such practice as I often use 0/1.
This is all overrided by your project/company coding practices or guidelines, if that's the case.
Why do both returns work?
In C, any non-zero value is considered to be true (this includes negative values) in a boolean context, whereas 0 is considered to be false as can be seen in N1570 Committee Draft of April 12, 2011 ISO/IEC 9899:201x:
§6.3.1.2 Boolean type
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.59)
Footnotes
59) NaNs do not compare equal to 0 and thus convert to 1.

Can two implementation defined identical expressions give different results?

Related to: Three questions: Is NULL - NULL defined? Is (uintptr_t)NULL - (uintptr_t)NULL defined?
Lets consider:
Case 1:
(uintptr_t)NULL - (uintptr_t)NULL will the result always be zero?
Case 2 (ispired by the Eric comment):
uintptr_t x = (uintptr_t)NULL;
will x - x be always zero?
case 3:
uintptr_t x = (uintptr_t)NULL, y = (uintptr_t)NULL;
Will x-y be always zero?
Case 4:
void *a;
/* .... */
uintptr_t x = (uintptr_t)a, y = (uintptr_t)a;
Will x-y be always zero?
If not - why?
Can two implementation defined identical expressions give different results?
Yes. It's "implementation-defined" - all rules are up to implementation. An imaginary implementation may look like this:
int main() {
void *a = 0;
#pragma MYCOMPILER SHIFT_UINTPTR 0
printf("%d\n", (int)(uintptr_t)a); // prints 0
#pragma MYCOMPILER SHIFT_UINTPTR 5
printf("%d\n", (int)(uintptr_t)a); // prints 5
}
Still such an implementation would be insane on most platforms.
I could imagine a example: architecture that has to deal with memory in "banks". A compiler for that architecture uses a #pragma switch to select the "bank" that is used for dereferencing pointers.
(uintptr_t)NULL - (uintptr_t)NULL will the result always be zero?
Not necessarily.
will x - x be always zero?
Yes. uintptr_t is an unsigned integer type, it has to obey the laws of mathematics.
Will x-y be always zero?
Not necessarily.
Will x-y be always zero?
Not necessarily.
If not - why?
The result of conversion from void* to uintptr_t is implementation defined - the implementation may convert the pointer value to different uintptr_t value each time, which would result in a non-zero difference between the values.
I could see a example: on some imaginary architecture pointers have 48-bits, while uintptr_t has 64-bits. A compiler for such architecture just "doesn't care" what is in those 16 extra bits and when converting uintptr_t to a pointer it uses only the 48-bits. When converting pointer to an uintrpt_t compiler uses whatever garbage value was leftover in registers for the extra 16-bits, because it's fast to do that in that specific architecture and because they will never be used when converting back..
You won't find a system in use anywhere where NULL isn't defined as some form of 0, be it the literal value or a void * with value 0, so all of your checks will either work as you'd expect or be syntax errors (can't subtract void * values).
Is it possible to be defined as anything else though? Theoretically. Though it's still a constant, so subtracting them (language and type allowing) will still equal 0.

Why the linux kernel uses double logical negations instead of casts to bools?

Given that x is a variable of type int with the number 5 as its value, consider the following statement:
int y = !!x;
This is what I think it happens: x is implicitly casted to a bool and the first negation is executed, after that the last negation is made, so a cast and two negations.
My question is, isn't just casting to bool (executing int y = (bool)x; instead of int y = !!x) faster than using double negation, as you are saving two negations from executing.
I might be wrong because I see the double negation a lot in the Linux kernel, but I don't understand where my intuition goes wrong, maybe you can help me out.
There was no bool type when Linux was first written. The C language treated everything that was not zero as true in Boolean expressions. So 7, -2 and 0xFF are all "true". No bool type to cast to. The double negation trick ensures the result is either zero or whatever bit pattern the compiler writers chose to represent true in Boolean expressions. When you're debugging code and looking at memory and register values, it's easier to recognize true values when they all have the same bit patterns.
Addendum: According the C89 draft standard, section 3.3.3.3:
The result of the logical negation operator ! is 0 if the value of its operand compares unequal to 0, 1 if the value of its operand compares equal to 0. The result has type int . The expression !E is equivalent to (0==E).
So while there was no Boolean type in the early days of the Linux OS, the double negation would have yielded either a 0 or a 1 (thanks to Gox for pointing this out), depending on the truthiness of the expression. In other words any bit pattern in the range of INT_MIN..-1 and 1..INT_MAX would have yielded a 1 and the zero bit pattern is self-explanatory.
C language unlike other languages does not have bool type. bool in C is actually defined in stdbool.h which is not included in many C projects. Linux kernel is one such projects, it would be a pain to go through Linux code and update everything to use bool now as well. That is reason why Linux kernel does not use bool in C.
why !!x? This is done to ensure that value of y is either 1 or 0. As an example if you have this cocd
x=5;
int y = !!x;
We know that everything that non-zero values in C mean true. So above code would brake down to y= !!(5) followed by y = !(0) and than y = 1.
EDIT:
One more thing, I just saw OP mentioned casting to bool. In C there is no bool as base type, bool is defined type, thus compilers do not cast integers to Boolean type.
EDIT 2:
To further explain, in C++, Java and other languages when you type bool a = false you do not have to use headers or compile some other libraries or define bool type for bool type to work, it is already incorporated into compilers, where as in c you have to.
EDIT 3:
bool is not the same as _Bool.
The only reason I can imagine is because this saves some typing (7 chars vs 2 chars).
As #jwdonahue and #Gox have already mentioned, this is not the correct reason. C did not have bool when the linux kernel was written therefore casting to bool was not an option.
As far as efficiency goes, both are equivalent because compilers can easily figure this out. See https://godbolt.org/g/ySo6K1
bool cast_to_bool_1(int x) {
return !!x;
}
bool cast_to_bool_2(int x) {
return (bool) x;
}
Both the functions compile to the same assembly which uses the test instruction to check if the argument is zero or not.
test edi, edi // checks if the passed argument is 0 or not
setne al // set al to 0 or 1 based on the previous comparison
ret // returns the result

Is there any possibility of divide-by-zero in this conditional statement?

This is tricking my mind a little bit, because i can't seem to find any problem with this code.
Anyways, here's the riddle:
Suppose someone injects a random value into a, b:
int foo(int a, int b)
{
return b ? (a / b): 0;
}
b != 0 always!
Is it possible for an integer zero division exception to occur?
I'm starting to think this is a prank, yet....
NOTE:
This question was published in a conference, there is a possibility that the author was specific to a compiler/architecture where this is problematic.
No, divide by zero is not possible here.
Quoting C11, chapter §6.5.15, Conditional operator , (emphasis mine)
The first operand is evaluated; there is a sequence point between its evaluation and the
evaluation of the second or third operand (whichever is evaluated). The second operand
is evaluated only if the first compares unequal to 0; the third operand is evaluated only if
the first compares equal to 0; [...]
So, in case, b is 0, the expression (a/b) will not be evaluated.
That said, just as note:
The division is integer division.
If you have a wrapper, that ensures b != 0, then you could cut down the whole function call and simply write someVar = a/b;
Also, I don't know of any architecture which (possibly) changes the aforesaid behavior.
There is no possibility for a division by 0 in your example, yet there is another special case you should check for: dividing INT_MIN by -1 may cause a division overflow, and usually causes an fatal exception on Intel hardware, a surprising behavior, yet consistent with the C Standard that specifies that integer overflow can cause an implementation specific behavior.
If you need to protect against such unwanted behavior, you must special case these operands and handle them specifically:
#include <limits.h>
int foo(int a, int b) {
if (b == 0) return 0;
if (a == INT_MIN && b == -1) return INT_MAX;
return a / b;
}
Since the values of a and b can be crafted by an external source, you definitely need to worry about division overflow. It is a fun game to play to try a crash unsafe calculators by feeding them these values.

What doe this C code do with (unsigned) and (long) cast [duplicate]

This question already has answers here:
!! c operator, is a two NOT?
(4 answers)
What is "!!" in C? [duplicate]
(7 answers)
Closed 8 years ago.
doing some exam prep and this is a past question.
Describe what the following pieces of C do and re write in a simple programming style with the same functionality.
(The bad indentation was the intention of the question).
With regards to section A i'm not sure what unsigned cast is doing to a. I have tested it a few times and can't seem to get a result that makes sense.
Similarly In B im not sure what how the while loop is working with the long cast and the !! being another problem
The Code :
//code section A
int f(int a,int b){
return(((unsigned) a)>b);}
//code section B
int h(int *x, int y){
int * z= x-- +y;
w=0;
while( (long) z-- ^(long) x) w += !!(*z);
return w;}
Any help would be appreciated, Thank you.
!! negates a boolean expression twice, essentially converting an expressions value to 0 or 1.
As in C all values other than zero mean true, and zero means false, !! can be used to convert it into 0 or 1, in the case you need to use it later in a function or expression which doesn't accept any value for true, only the number 1.
About the rest: unsigned interprets the internal representation of your int a from your function argument to unsigned int, so for example -1 becomes 4294967295 if your compiler uses two's complement and 4 byte ints.
About the casting to long : I strongly recommend against in similar situations unless you absolutely know what you are doing. In your example, it does some pointer arithmetic, in interpreting your pointer as numeric values, essentially working with the addresses of your variables as if they were just numbers. They have probably chosen long because on their system it had the exact same size as a pointer. This is not guaranteed to be so on all systems.
So, to give a very short answer to your question: The code does undefined behavior with those expressions, except for the !! which just give 0 if the expression was zero, and 1 otherwise.
The operator ! is the logical negation.
!true is false (0), and !false is true (1).
When a value is used as a boolean value, anyhting other than 0 (0 in a large sense) is true; 0 is false.
So, !!(*z) has either the value 0 or 1.
It will be 0 if *z was NULL to begin with
It will be 1 if *z was not NULL.
! is the boolean operator for not.
false is 0, and true is 1 in C.
So when you take any int, which is not 0- and you run ! on it, you'll get 0 (true becomes false), and zero will become one .
So the action of !! is changing each non-zero value to 1 , and leaving each 0 a 0.

Resources