It seems so strange. I found misunderstanding. I use gcc with char as signed char. I always thought that in comparison expressions(and other expressions) signed value converts to unsigned if necessary.
int a = -4;
unsigned int b = a;
std::cout << (b == a) << std::endl; // writes 1, Ok
but the problem is that
char a = -4;
unsigned char b = a;
std::cout << (b == a) << std::endl; // writes 0
what is the magic in comparison operator if it's not just bitwise?
According to the C++ Standard
6 If both operands are of arithmetic or enumeration type, the usual
arithmetic conversions are performed on both operands; each of the
operators shall yield true if the specified relationship is true and
false if it is false.
So in this expression
b == a
of the example
char a = -4;
unsigned char b = -a;
std::cout << (b == a) << std::endl; // writes 0
the both operands are converted to type int. As the result signed char propagets its signed bit and two values become unequal.
To demonstrate the effect try to run this simple example
{
char a = -4;
unsigned char b = -a;
std::cout << std::hex << "a = " << ( int )a << "'\tb = " << ( int )b << std::endl;
if ( b > a ) std::cout << "b is greater than a, that is b is positive and a is negative\n";
}
The output is
a = fffffffc' 'b = 4
b is greater than a, that is b is positive and a is negative
Edit: Only now I have seen that definitions of the variables have to look as
char a = -4;
unsigned char b = a;
that is the minus in the definition of b ahould not be present.
Since an (unsigned) int is at least 16 bits wide, let's use that for instructional purposes:
In the first case: a = 0xfffc, and b = (unsigned int) (a) = 0xfffc
Following the arithmetic conversion rules, the comparison is evaluated as:
((unsigned int) b == (unsigned int) a) or (0xfffc == 0xfffc), which is (1)
In the 2nd case: a = 0xfc, and b = (unsigned char) ((int) a) or:
b = (unsigned char) (0xfffc) = 0xfc i.e., sign-extended to (int) and truncated
Since and int can represent the range of both the signed char and unsigned char types, the comparison is evaluated as: (zero-extended vs. sign-extended)
((int) b == (int) a) or (0x00fc == 0xfffc), which is (0).
Note: The C and C++ integer conversion rules behave the same way in these cases. Of course, I'm assuming that the char types are 8 bit, which is typical, but only the minimum required.
They both output 0 because unsigned values can get converted to signed values, not viceversa (like you said).
Related
int main() {
unsigned i = 5;
int j = -10;
double d = i + j;
long l = i + j;
int k = i + j;
std::cout << d << "\n"; //4.29497e+09
std::cout << l << "\n"; //4294967291
std::cout << k << "\n"; //-5
std::cout << i + j << "\n"; //4294967291
}
I believe signed int is promoted to unsigned before doing the arithmetic operators.
While -10 is converted to unsigned unsigned integer underflow (is this the correct term??) will occur and after addition it prints 4294967291.
Why this is not happening in the case of int k which print -5?
The process of doing the arithmetic operator involves a conversion to make the two values have the same type. The name for this process is finding the common type, and for the case of int and unsigned int, the conversions are called usual arithmetic conversions. The term promotion is not used in this particular case.
In the case of i + j, the int is converted to unsigned int, by adding UINT_MAX + 1 to it. So the result of i + j is UINT_MAX - 4, which on your system is 4294967291.
You then store this value in various data types; the only output that needs further explanation is k. The value UINT_MAX - 4 cannot fit in int. This is called out-of-range assignment and the resulting value is implementation-defined. On your system it apparently assigns the int value which has the same representation as the unsigned int value.
j will be converted to unsigned int before addition, and this happens in all your i + j. A quick experiment.
In the case of int k = i + j. As in the case of your implementation and mine, i + j produces: 4294967291. 4294967291 is larger than std::numeric_limits<int>::max(), the behavior is going to be implementation defined. Why not try assigning 4294967291 to an int?
#include <iostream>
int main(){
int k = 4294967291;
std::cout << k << std::endl;
}
Produces:
-5
As seen Here
I've written a simple Fibonacci sequence generator that looks like:
#include <iostream>
void print(int c, int r) {
std::cout << c << "\t\t" << r << std::endl;
}
int main() {
unsigned long long int a = 0, b = 1, c = 1;
for (int r = 1; r <= 1e3; r += 1) {
print(c, r);
a = b;
b = c;
c = a + b;
}
}
However, as r gets around the value of 40, strange things begin to happen. c's value oscillate between negative and positive, despite the fact he's an unsigned integer, and of course the Fibonacci sequence can't be exactly that.
What's going on with unsigned long long integers?
Does c get too large even for a long long integer?
You have a narrowing conversion here print(c, r); where you defined print to take only int's and here you pass an unsigned long long. It is implementation defined.
Quoting the C++ Standard Draft:
4.4.7:3: If the destination type is signed, the value is
unchanged if it can be represented in the destination type; otherwise,
the value is implementation-defined.
But what typically happens is that: from the unsigned long long, only the bits that are just enough to fit into an int are copied to your function. The truncated int is stored in Twos complements, depending on the value of the Most Significant Bit. you get such alternation.
Change your function signature to capture unsigned long long
void print(unsigned long long c, int r) {
std::cout << c << "\t\t" << r << std::endl;
}
BTW, see Mohit Jain's comment to your question.
int a = 5 , b = 2 ;
double ans1 = a / b ; // ans1 = 2
cout << setprecision ( 4 ) << fixed << ans1 << endl ;
unsigned short int c = USHRT_MAX , d = USHRT_MAX ;
unsigned int ans2 = c + d ; // ans2 = 131070
cout << ans2 ;
What happens when the ( a / b ) is evaluated?
1) the result first stored in int ( variable type on the R.H.S ) and then converted into 64-bit double ( variable type on the L.H.S ) and then stored in the ans1 or first variables are converted into 64-bit double ( variable type on the L.H.S ) and then / takes place ?
2) if first evaluated as the variables type on R.H.S , then how the second one prints the correct ans ( because the ans is out of unsigned short int's limit )
In the first example, you first divide the two ints with truncating integer division and then assign the result of that (2) to ans1.
The second case is different in a subtle way: You chose integer types that are smaller than int. Thus, before any arithmetic operator acts on them, they both get converted to int (if that fits, as it does here, to unsigned int otherwise) while preserving their values, and on int the operation you showed does not overflow. Then you assign the result (which has type int) to the unsigned int, and since it is non-negative, nothing strange happens.
If you tried the second example with unsigned int instead of unsigned short, you could observe the "integer overflow" (which is no real overflow because unsigned arithmetic wraps).
I tried running the following code code:
char c = (2 << 7) >> 7
which should return 0 because 2 has this binary representation as a char:
0 0 0 0 0 0 1 0
After 7 shifts left, we get
0 0 0 0 0 0 0 0
Then, after seven shifts right, we get
0 0 0 0 0 0 0 0
However, I'm getting the result as 2, not 0.
The compiler says that 2 << 7 is 256, but it's a char and so it shouldn't be 256.
I understand that the 2 << 7 will be calculated as ints and the answer will be put into c so 256 >> 7 is 2.
I tried to cast 2 to char (ex: (char)2>>7) but it doesn't work either.
I'm trying to extract each bit from the char, so I wrote this code:
char c = 0x02;
for(int i=0;i<7;i++)
{
char current = (c<<i)>>7;
}
How can I get each bit? What's wrong with my way?
The result of an arithmetic shift operation with one operand being an int in C++ is always an int. Therefore, when you write
current = (c << i) >> 7;
C++ will interpret (c << i) and (c << i) >> 7 as ints, casting back to a char only when the assignment is done. Since the temporary values are ints, no overflow occurs and the result should come out to the integer result casted to a char.
Hope this helps!
To get each bit, you could write:
(c >> i) & 0x01
Advantage: It works for any integer type.
According to 5.8 [expr.shift] paragraph 1:
... The operands shall be of integral or unscoped enumeration type and integral promotions are performed. The type of the result is that of the promoted left operand. ...
This for a left argument of type char together with the rules on integer promotion (4.5 [conv.prom]) says that the result is int. Of course, an int can hold the result of 2 << 7. You can easily verify this behavior, too:
#include <iostream>
void print(char c) { std::cout << "char=" << int(c) << "\n"; }
void print(int i) { std::cout << "int=" << i << "\n"; }
int main()
{
print(2 << 7);
}
The most simple approach to get the bits of a value is to use a std::bitset<N> with N being the digits of the corresponding unsigned type, e.g.:
char c('a');
std::bitset<std::numeric_limits<unsigned char>::digits> bits(c);
If you want to get bits yourself you'd mask the bits using its unsigned counterpart of the integer type, e.g.:
template <typename T>
void get_bits(T val)
{
typedef typename std::make_unsigned<T>::type U;
U value(val);
for (std::size_t s(std::numeric_limits<U>::digits); s-- != 0; ) {
std::cout << bool(value & (1u << s));
}
std::cout << '\n';
}
I just want to know how to convert an hexadecimal value contained in a char (byte) into an integer. I want to convert the color buffer from a .bmp file which is of course in hexadecimal and convert it in integers.
For example :
char rgb_hexa[3] = {0xA8, 0xF4, 0xD3};
After conversion :
int rgb_int[3] = {168, 244, 211};
I always tried to use strtol but it seems to only works with char *. I tried to do the following test but it does not work :
char src_hexa_red = 0xA8;
char src_hexa_green = 0xF4;
char src_hexa_blue = 0xD3;
std::cout << "R=" << strtol(&src_hexa_red, (char**)NULL, 16) << ", G="
<< strtol(&src_hexa_green, (char**)NULL, 16) << ", B="
<< strtol(&src_hexa_blue, (char**)NULL, 16) << std::endl;
Does anyone can help me please ?
Thanks in advance for your help.
A single char never contains hexadecimal. Nor decimal, for
that matter. Strictly speaking, a char contains an integral
value; the C++ standard requires it to use a binary
representation for the value. The value can be interpreted as
a character, but this is not always the case; there are contexts
where the integral value is used directly.
Hexadecimal and decimal are just ways of representing the value
in text format. They only have meaning when dealing with text.
for(int i = 0; i < 3; ++i)
rgb_int[i] = (unsigned char)rgb_hexa[i];
char is an integer type in C & C++ just like short, int and long. It's just the smallest integer type. Mostly, char is signed & the maximum which can fit is 127. So if the hex value was below or equal to 127, you wouldn't have to do anything. However, in this case the hex values you have are > 127 - hence you would have to cast them to unsigned to get the value you want.
Note that both the statements are identical to the compiler.
char rgb_hexa[3] = {0xA8, 0xF4, 0xD3};
char rgb_hexa[3] = {168, 244, 211};
You could have even used octal if you wanted
char rgb_hexa[3] = {0250, 0364, 0323};
It's all the same.
The values in the char array are already in a binary form, so you can cast them to an int, if you need them as such.
int v = (int)rgb_hexa[0];
You should be aware though that using signed char they will be sign extendend.
So 0xFA becomes 0xFFFFFFFA when converted to an int.
If you want to keep the values then you should use unsigned char and unsigned int which makes it 0x000000FA depending on how you want to use the values.
int v0 = (int)a[1]; <-- sign extended
unsigned int v1 = (unsigned int)a[1]; <-- sign extended
unsigned int v1 = (unsigned int)((unsigned char *)a)[1]; <-- not sign extended
You don't need to do any conversion because hexa/decimal are just ways to represent values.
For example 0xA8 in hexadecimal is the same value as 180 in decimal and 250 in octal. As in languages for example, "two", "deux" and "dois" represent all the same number (2).
In your case if you want to print the values do the following:
short y = (short) x & 0x00FF; // x is the char you want to print
cout << "Value (decimal): " << y;
cout << "Value (hexa): " << hex << y;
cout << "Value (oct): " << oct << y;
Why can't you do this
int main(int argc, char *argv[])
{
char rgb_hexa[3] = {0xA8, 0xF4, 0xD3};
int rgb_int[3] = {0,};
int i = 0;
for( i = 0 ; i < 3 ;i++)
rgb_int[i] = (unsigned char)rgb_hexa[i];
for( i = 0 ; i < 3 ;i++)
printf("%d ",rgb_int[i]);
return 0;
}
pretty straight forward ..
For type conversion, there is static_cast:
unsigned char source = 168; // note that this has for compiler same meaning as:
// unsigned char source = 0xA8; // because data is stored in binary anyway
unsigned int dest = static_cast<int>(source); // the conversion
std::cout << source << std::endl;
dest and source have same binary meaning, but they are of a different type.
I've used unsigned types, because signed char stores usually values from -127 to 127, see limits.