While implementing logical operations in the code, I discovered a phenomenon where it should not be entered in the if statement.
It turns out that this is the AND (&&) operation of -1 and natural numbers.
I don't know why the value 1 is printed in the same code below.
I ran direct calculations such as 1's complement and 2's complement, but no 1 came out.
#include <iostream>
using namespace std;
int main()
{
int a = 10;
int b = -1;
int c = a && b;
printf("test = %d",c);
return 0;
}
The expression a && b is a bool type and is either true or false: it is true if and only if both a and b are non-zero, and false otherwise. As your question mentions complementing schemes (note that from C++20, an int is always 2's complement), -0 and +0 are both zero for the purpose of &&.
When assigned to the int type c, that bool type is converted implicitly to either 0 (if false) or 1 (if true).
(In C the analysis is similar except that a && b is an int type, and the implicit conversion therefore does not take place.)
Related
I am interrested wheather standard says anything about possible values of bool type type after casting it to integer type.
For example following code:
#include <iostream>
using namespace std;
int main() {
bool someValue=false;
*((int*)(&someValue)) = 50;
cout << someValue << endl;
return 0;
}
prints 1 even though it's forced to store value 50. Does standard specify anything about it? Or is compiler generating some method for type bool as:
operator int(){
return myValue !=0 ? 1 : 0;
}
Also why is casting like following:
reinterpret_cast<int>(someValue) = 50;
forbidden with error
error: invalid cast from type 'bool' to type 'int'
(For all above I user GCC 5.1 compiler.)
The way you are using it exhibits UB, because you write outside of the bool variable's boundaries AND you break strict aliasing rule.
However, if you have a bool and want to use it as a an int (this usually happens when you want to index into an array based on some condition), the standard mandates that a true bool converts into 1 and false bool converts into 0, no matter what (UB obviously excluded).
For example, this is guaranteed to output 52 as long as should_add == true.
int main(){
int arr[] = {0, 10};
bool should_add = 123;
int result = 42 + arr[should_add];
std::cout << result << '\n';
}
This line *((int*)(&someValue)) = 50; is at least non standard. The implementation could use a lesser rank for bool (say 1 or 2 bytes) that for int (say 4 bytes). In that case, you would write past the variable possibly erasing an other variable.
And anyway, as you were said in comment, thanks to the strict aliasing rule almost any access through a casted pointer can be seen as Undefined Behaviour by a compiler. The only almost legal one (for the strict aliasing rule) would be:
*((char *) &someValue) = 50;
on a little endian system, and
*(((char *) &someValue) + sizeof(bool) - 1) = 50;
on a big endian one (byte access has still not be forbidden).
Anyway, as the representation of bool is not specified by the standard directly writing something in a bool can lead to true or false depending on implementation. For example an implementation could considere only the lowest level bit (true if val&1 is 1, else 0), another one could considere all bits (true for any non 0 value, false for only 0). The only thing that standard says is that a conversion of a 0 leads to false and of a non 0 leads to true.
But was is mandated by standard is the conversion from bool to int:
4.5 Integral promotions [conv.prom]
...A prvalue of type bool can be converted to a prvalue of type int, with false becoming zero and true
becoming one.
So this fully explains that displaying a bool can only give 0 or 1 - even if as the previous operation invoked UB, anything could have happen here including this display
You invoked Undefined Behaviour - shame on you
I have a code that is being changed to compile in a 64-bit mode where previously it was being compiled in Win32 for various reasons. This has caused some cleanup work to address some warnings, so I'm picking through code and found something that looks like this:
class foo
{
public:
int foo() { return data_.size()-1; }
private:
std::vector<int> data_;
};
The size() method on STL containers returns unsigned values. The return value is being cast into a signed integer value so there's a conversion that will occur at some point.
I'm not sure about the precedence here though. Will the value that size() is returning get cast to an int and then have 1 subtracted, which would result in the return value being -1 if size was zero? Or will we subtract 1 from an unsigned int, possibly doing bad things if the container is empty when this gets called?
Thanks!
It will be unsigned = unsigned - 1; return signed(unsigned) where unsigned(0) - 1 == unsigned(max)
From 4.7 Integral conversions
A prvalue of an integer type can be converted to a prvalue of another
integer type. A prvalue of an unscoped enumeration type can be
converted to a prvalue of an integer type. If the destination type is
unsigned, the resulting value is the least unsigned integer congruent
to the source integer (modulo 2n where n is the number of bits used to
represent the unsigned type). [ Note: In a two’s complement
representation, this conversion is conceptual and there is no change
in the bit pattern (if there is no truncation). — end note ] If the
destination type is signed, the value is unchanged if it can be
represented in the destination type (and bit-field width); otherwise,
the value is implementation-defined.
Hence any unsigned value greater than the maximum signed value leads to implementation defined behavior.
If the size is 0 the result is not -1 but a very large integer "18446744073709551615" (unsigned(max)).
#include <vector>
#include <iostream>
int main()
{
std::vector<int> nums {};
std::cout << "nums contains " << nums.size()-1 << " elements.\n";
// nums contains 18446744073709551615 elements.
}
http://coliru.stacked-crooked.com/a/a69d4af99ba77f47
When data_.size()-1 is evaluated as an unsigned integer. When data_.size() is 0, the function could return a very large positive number instead of -1.
Your best option:
int foo() { int s = data_.size(); return s-1; }
The next program returns i=-1. The bit pattern of std::numeric_limits<unsigned>::max() is that one of the int -1. This is the reason why your code works in w32.
#include <iostream>
#include <limits>
int main() {
std::cout << "i=" << static_cast<int>(std::numeric_limits<unsigned>::max()) << '\n';
}
/*
Local Variables:
compile-command: "g++ test.cc -o a.exe && ./a.exe"
End:
*/
But, you rely in your code on the translation of signed integral types and unsigned ones. The types must fit! Therefore, better use std::ptrdiff_t and std::size_t.
#include <iostream>
#include <limits>
int main() {
std::cout << "i=" << static_cast<std::ptrdiff_t>(std::numeric_limits<std::size_t>::max()) << '\n';
}
/*
Local Variables:
compile-command: "g++ test.cc -o a.exe && ./a.exe"
End:
*/
Your second guess is correct. In general, evaluating any expression of the form
exp1 op exp2
works in the steps
evaluate exp1
evaluate exp2
apply op on the values of exp1 and exp2
Note: steps 1 and 2 can occur in any sequence. The point is each operand is evaluated before applying the operator.
So in this case exp1 will evaluated as an unsigned int value first, and may have undesirable effect.
This question already has answers here:
Can I assume (bool)true == (int)1 for any C++ compiler?
(5 answers)
Closed 8 years ago.
Consider the code
bool f() { return 42; }
if (f() == 1)
printf("hello");
Does C (C99+ with stdbool.h) and C++ standards guarantee that "hello" will printed? Does
bool a = x;
is always equivalent to
bool a = x ? 1 : 0;
Yes. You are missing a step though. "0" is false and every other int is true, but f() always returns true ("1"). It doesn't return 42, the casting occurs in "return 42;".
In C macro bool (we are speaking about the macro defined in stdbool.h) expands to _Bool that has only two values 0 and 1.
In C++ the value of f() in expression f() == 1 is implicitly converted to int 1 according to the integral promotion.
So in my opinion this code
bool f() { return 42; }
if (f() == 1)
printf("hello");
is safe.
In C++, bool is a built-in type. Conversions from any type to bool always yield false (0) or true (1).
Prior to the 1999 ISO C standard, C did not have a built-in Boolean type. It was (and still is) common for programmers to define their own Boolean types, for example:
typedef int BOOL;
#define FALSE 0
#define TRUE 1
or
typedef enum { false, true } bool;
Any such type is at least 1 byte in size, and can store values other than 0 or 1, so equality comparisons to 0 or 1 are potentially unsafe.
C99 added a built-in type _Bool, with conversion semantics similar to those for bool in C++; it can also be referred to as bool if you have #include <stdbool.h>.
In either C or C++, code whose behavior is undefined can potentially store a value other than 0 or 1 in a bool object. For example, this:
bool b;
*(char*)&b = 2;
will (probably) store the value 2 in b, but a C++ compiler may assume that its value is either 0 or 1; a comparison like b == 0 or b == true may either succeed or fail.
My advice:
Don't write code that stores strange values in bool objects.
Don't compare bool values for equality or inequality to 0, 1, false, or true.
In your example:
bool f() { return 42; }
Assuming this is either C++ or C with <stdbool.h>, this function will return true or, equivalently, 1, since the conversion of 42 to bool yields 1.
if (f() == 1)
printf("hello");
Since you haven't constructed any strange bool values, this is well behaved and will print "hello".
But there's no point in making the comparison explicitly. f() is already of type bool, so it's already usable as a condition. You can (and probably should) just write:
if (f())
printf("hello");
Writing f() == 1 is no more helpful than writing (f() == 1) == 1).
In a real program, presumably you'll have given your function a meaningful name that makes it clear that its value represents a condition:
if (greeting_required())
printf("hello");
The only real trick that I know of, that is useful with pre-C99 environments is the double negation
int a = 42;
if ( (!!a) != 0 ) printf("Hello\n");
this will print Hello because the result of the !! operation is a boolean that is true when the value is non-zero, false otherwise. But this is gonna cost you 2 negation to get the boolean that you want, in modern standards this is redundant because you will get the same result without the !! and it's a result granted by the language.
I'm trying to understand why the following code doesn't issue a warning at the indicated place.
//from limits.h
#define UINT_MAX 0xffffffff /* maximum unsigned int value */
#define INT_MAX 2147483647 /* maximum (signed) int value */
/* = 0x7fffffff */
int a = INT_MAX;
//_int64 a = INT_MAX; // makes all warnings go away
unsigned int b = UINT_MAX;
bool c = false;
if(a < b) // warning C4018: '<' : signed/unsigned mismatch
c = true;
if(a > b) // warning C4018: '<' : signed/unsigned mismatch
c = true;
if(a <= b) // warning C4018: '<' : signed/unsigned mismatch
c = true;
if(a >= b) // warning C4018: '<' : signed/unsigned mismatch
c = true;
if(a == b) // no warning <--- warning expected here
c = true;
if(((unsigned int)a) == b) // no warning (as expected)
c = true;
if(a == ((int)b)) // no warning (as expected)
c = true;
I thought it was to do with background promotion, but the last two seem to say otherwise.
To my mind, the first == comparison is just as much a signed/unsigned mismatch as the others?
When comparing signed with unsigned, the compiler converts the signed value to unsigned. For equality, this doesn't matter, -1 == (unsigned) -1. For other comparisons it matters, e.g. the following is true: -1 > 2U.
EDIT: References:
5/9: (Expressions)
Many binary operators that expect
operands of arithmetic or enumeration
type cause conversions and yield
result types in a similar way. The
purpose is to yield a common type,
which is also the type of the result.
This pattern is called the usual
arithmetic conversions, which are
defined as follows:
If either
operand is of type long double, the
other shall be converted to long
double.
Otherwise, if either operand
is double, the other shall be
converted to double.
Otherwise, if
either operand is float, the other
shall be converted to float.
Otherwise, the integral promotions
(4.5) shall be performed on both
operands.54)
Then, if either operand
is unsigned long the other shall be
converted to unsigned long.
Otherwise, if one operand is a long
int and the other unsigned int, then
if a long int can represent all the
values of an unsigned int, the
unsigned int shall be converted to a
long int; otherwise both operands
shall be converted to unsigned long
int.
Otherwise, if either operand is
long, the other shall be converted to
long.
Otherwise, if either operand
is unsigned, the other shall be
converted to unsigned.
4.7/2: (Integral conversions)
If the destination type is unsigned,
the resulting value is the least
unsigned integer congruent to the
source integer (modulo 2n where n is
the number of bits used to represent
the unsigned type). [Note: In a two’s
complement representation, this
conversion is conceptual and there is
no change in the bit pattern (if there
is no truncation). ]
EDIT2: MSVC warning levels
What is warned about on the different warning levels of MSVC is, of course, choices made by the developers. As I see it, their choices in relation to signed/unsigned equality vs greater/less comparisons make sense, this is entirely subjective of course:
-1 == -1 means the same as -1 == (unsigned) -1 - I find that an intuitive result.
-1 < 2 does not mean the same as -1 < (unsigned) 2 - This is less intuitive at first glance, and IMO deserves an "earlier" warning.
Why signed/unsigned warnings are important and programmers must pay heed to them, is demonstrated by the following example.
Guess the output of this code?
#include <iostream>
int main() {
int i = -1;
unsigned int j = 1;
if ( i < j )
std::cout << " i is less than j";
else
std::cout << " i is greater than j";
return 0;
}
Output:
i is greater than j
Surprised? Online Demo : http://www.ideone.com/5iCxY
Bottomline: in comparison, if one operand is unsigned, then the other operand is implicitly converted into unsigned if its type is signed!
The == operator just does a bitwise comparison (by simple division to see if it is 0).
The smaller/bigger than comparisons rely much more on the sign of the number.
4 bit Example:
1111 = 15 ? or -1 ?
so if you have 1111 < 0001 ... it's ambiguous...
but if you have 1111 == 1111 ... It's the same thing although you didn't mean it to be.
Starting from C++20 we have special functions for correct comparing signed-unsigned values
https://en.cppreference.com/w/cpp/utility/intcmp
In a system that represents the values using 2-complement (most modern processors) they are equal even in their binary form. This may be why compiler doesn't complain about a == b.
And to me it's strange compiler doesn't warn you on a == ((int)b). I think it should give you an integer truncation warning or something.
The line of code in question does not generate a C4018 warning because Microsoft have used a different warning number (i.e. C4389) to handle that case, and C4389 is not enabled by default (i.e. at level 3).
From the Microsoft docs for C4389:
// C4389.cpp
// compile with: /W4
#pragma warning(default: 4389)
int main()
{
int a = 9;
unsigned int b = 10;
if (a == b) // C4389
return 0;
else
return 0;
};
The other answers have explained quite well why Microsoft might have decided to make a special case out of the equality operator, but I find those answers are not super helpful without mentioning C4389 or how to enable it in Visual Studio.
I should also mention that if you are going to enable C4389, you might also consider enabling C4388. Unfortunately there is no official documentation for C4388 but it seems to pop up in expressions like the following:
int a = 9;
unsigned int b = 10;
bool equal = (a == b); // C4388
Strange question, but someone showed me this,
I was wondering can you use the not ! operator for int in C++? (its strange to me).
#include <iostream>
using namespace std;
int main()
{
int a=5, b=4, c=4, d;
d = !( a > b && b <= c) || a > c && !b;
cout << d;
system ("pause");
return 0;
}
Yes. For integral types, ! returns true if the operand is zero, and false otherwise.
So !b here just means b == 0.
This is a particular case where a value is converted to a bool. The !b can be viewed as !((bool)b) so the question is what is the "truthness" of b. In C++, arithmetic types, pointer types and enum can be converted to bool. When the value is 0 or null, the result is false, otherwise it is true (C++ §4.1.2).
Of course custom classes can even overload the operator! or operator<types can be convert to bool> to allow the !b for their classes. For instance, std::stream has overloaded the operator! and operator void* for checking the failbit, so that idioms like
while (std::cin >> x) { // <-- conversion to bool needed here
...
can be used.
(But your code !( a > b && b <= c) || a > c && !b is just cryptic.)
Originally, in C (on which C++ is based) there was no Boolean type. Instead, the value "true" was assigned to any non-zero value and the value "false" was assigned to anything which evaluates to zero. This behavior still exists in C++. So for an int x, the expressions !x means "x not true", which is "x not non-zero", i.e. it's true if x is zero.
You can, !b is equivalent to (b == 0).
The test for int is true for non-zero values and false for zero values, so not is just true for zero values and false for non-zero values.
The build-in ! operator converts its argument to bool. The standard specifies that there exists a conversion from any arithmetic type(int, char,.... float, double...) to bool. If the source value is 0 the result is true, otherwise it is false