Hexdecimals in C - c

I'm confused. Why in this program a gives me 0xFFFFFFA0 but b gives me 0xA0? It's weird.
#include <stdio.h>
int main()
{
char a = 0xA0;
int b = 0xA0;
printf("a = %x\n", a);
printf("b = %x\n", b);
}

Default type of a is signed in char a = 0xA0; and in any signed data type whether its char of int you should be careful of sign bit, if sign bit is set means number will be negative and store as two's compliment way.
char a = 0xA0; /* only 1 byte for a but since sign bit is set,
it gets copied into remaining bytes also */
a => 1010 0000
|
this sign bit gets copied
1111 1111 1111 1111 1111 1111 1010 0000
f f f f f f A 0
In case of int b = 0xA0; sign bit(31st bit) is 0 so what ever it contains i.e 0xA0 will be printed.

Let's take this step-by-step.
char a = 0xA0;
0xA0 in an integer constant with a value of 160 and type int.
In OP's case, a char is encoded like a signed char with an 8-bit range. 160 is more than the maximum 8-bit char and so assigning an out-of-range value to a some signed integer type is implementation defined behavior. In OP's case, the value "wrapped around" and a took on the value of 160 - 256 or -96.
// Try
printf("a = %d\n", a);
With printf() (a variadic function), char a it passed to the ... part and so goes though the usual integer promotions to an int and retains the same value.
printf("a = %x\n", a);
// is just like
printf("a = %x\n", -96);
printf("a = %x\n", a);
With printf(), "%x" expect an unsigned or an int with a value in the non-negative range. With int and -96, it is neither and so the output is undefined behavior.
A typical undefined behavior is this case is to interpret the passed bit pattern as an unsigned. The bit pattern of int -96, as a 32-bit int is 0xFFFFFFA0.
Moral of the story:
Enable a compile warnings. A good compiler would warn about both char a = 0xA0; and printf("a = %x\n", a);
Do not rely on undefined behavior.

Related

%d for unsigned integer

I accidentally used "%d" to print an unsigned integer using an online compiler. I thought errors would pop out, but my program can run successfully. It's good that my codes are working, but I just don't understand why.
#include <stdio.h>
int main() {
unsigned int x = 1
printf( "%d", x);
return 0;
}
The value of the "unsigned integer" was small enough that the MSB (most significant bit) was not set. If it were, printf() would have treated the value as a "negative signed integer" value.
int main() {
uint32_t x = 0x5;
uint32_t y = 0xC0000000;
printf( "%d %u %d\n", x, y, y );
return 0;
}
5 3221225472 -1073741824
You can see the difference.
With new-fangled compilers that "read into" printf format specifiers and match those with the datatypes of following parameters, it may be that the online compiler may-or-may-not have been able to report this type mismatch with a warning. This may be something you will want to look into.
refer to printf() manual, they said:
A character that specifies the type of conversion to be applied. The
conversion specifiers and their meanings are:
d, i
The int argument is
converted to signed decimal notation. The precision, if any, gives the
minimum number of digits that must appear; if the converted value
requires fewer digits, it is padded on the left with zeros. The
default precision is 1. When 0 is printed with an explicit precision
0, the output is empty.
so it means that the parameter even if it's in unsigned representation, it will be converted into its signed int representation and printed, see the following code example:
#include <stdio.h>
int main(){
signed int x1 = -2147483648;
unsigned int x2 = -2147483648;
unsigned long long x3 = -2147483648;
printf("signed int x1 = %d\n", x1);
printf("unsigned int x2 = %d\n", x2);
printf("signed long long x3 = %d\n", x3);
}
and this is the output:
signed int x1 = -2147483648
unsigned int x2 = -2147483648
signed long long x3 = -2147483648
so it means no matter what is the type of the variable printed, as long as you specified %d as format specifier, the variable will be converted into its representation in signed int and be printed
in case of unsigned char like for example:
#include <stdio.h>
int main(){
unsigned char s = -10;
printf("s = %d",s);
}
the output is :
s = 246
as the binary representation of unsigned char s = -10 is :
1111 0110
where the MSB bit is 1, but when it's converted into signed int, the new representation is :
0000 0000 0000 0000 0000 0000 1111 0110
so the MSB is no longer have that 1 bit in its MSB which represents whether the number is positive or negative.

Char automatically converts to int (I guess)

I have following code
char temp[] = { 0xAE, 0xFF };
printf("%X\n", temp[0]);
Why output is FFFFFFAE, not just AE?
I tried
printf("%X\n", 0b10101110);
And output is correct: AE.
Suggestions?
The answer you're getting, FFFFFFAE, is a result of the char data type being signed. If you check the value, you'll notice that it's equal to -82, where -82 + 256 = 174, or 0xAE in hexadecimal.
The reason you get the correct output when you print 0b10101110 or even 174 is because you're using the literal values directly, whereas in your example you're first putting the 0xAE value in a signed char where the value is then being sort of "reinterpreted modulo 128", if you wanna think of it that way.
So in other words:
0 = 0 = 0x00
127 = 127 = 0x7F
128 = -128 = 0xFFFFFF80
129 = -127 = 0xFFFFFF81
174 = -82 = 0xFFFFFFAE
255 = -1 = 0xFFFFFFFF
256 = 0 = 0x00
To fix this "problem", you could declare the same array you initially did, just make sure to use an unsigned char type array and your values should print as you expect.
#include <stdio.h>
#include <stdlib.h>
int main()
{
unsigned char temp[] = { 0xAE, 0xFF };
printf("%X\n", temp[0]);
printf("%d\n\n", temp[0]);
printf("%X\n", temp[1]);
printf("%d\n\n", temp[1]);
return EXIT_SUCCESS;
}
Output:
AE
174
FF
255
https://linux.die.net/man/3/printf
According to the man page, %x or %X accept an unsigned integer. Thus it will read 4 bytes from the stack.
In any case, under most architectures you can't pass a parameter that is less then a word (i.e. int or long) in size, and in your case it will be converted to int.
In the first case, you're passing a char, so it will be casted to int. Both are signed, so a signed cast is performed, thus you see preceding FFs.
In your second example, you're actually passing an int all the way, so no cast is performed.
If you'd try:
printf("%X\n", (char) 0b10101110);
You'd see that FFFFFFAE will be printed.
When you pass a smaller than int data type (as char is) to a variadic function (as printf(3) is) the parameter is converted to int in case the parameter is signed and to unsigned int in the case it is unsigned. What is being done and you observe is a sign extension, as the most significative bit of the char variable is active, it is replicated to the thre bytes needed to complete an int.
To solve this and to have the data in 8 bits, you have two possibilities:
Allow your signed char to convert to an int (with sign extension) then mask the bits 8 and above.
printf("%X\n", (int) my_char & 0xff);
Declare your variable as unsigned, so it is promoted to an unsigned int.
unsigned char my_char;
...
printf("%X\n", my_char);
This code causes undefined behaviour. The argument to %X must have type unsigned int, but you supply char.
Undefined behaviour means that anything can happen; including, but not limited to, extra F's appearing in the output.

unsigned char and char XOR operation

Is there anyone can help me to explain what is the difference between unsigned char and char in XOR operation?
#include <stdio.h>
int main() {
char a[2] = { 0x56, 0xa5 }; // a[0] 0101 0110
// a[1] 1010 0101
a[0] = a[0] ^ a[1]; // a[0] 1111 0011 f3
printf("%02x", a[0]);
puts("");
unsigned char b[2] = { 0x56, 0xa5 }; // b[0] 0101 0110
// b[1] 1010 0101
b[0] = b[0] ^ b[1]; // b[0] 1111 0011 f3
printf("%02x", b[0]);
puts("");
}
result:
fffffff3
f3
[Finished in 0.0s]
Another example:
#include <stdio.h>
int main() {
char a[2] = { 0x01, 0x0a };
a[0] = a[0] ^ a[1];
printf("%02x", a[0]);
puts("");
unsigned char b[2] = { 0x01, 0x0a };
b[0] = b[0] ^ b[1];
printf("%02x", b[0]);
puts("");
}
result:
0b
0b
[Finished in 0.0s]
In the first case, your code
printf("%02x", a[0]);
Passes a char value to a variadic function printf. The char value is promoted to int type and passed as such. The value of a[0] is -13 because the char type happens to be signed by default on your environment, The value is preserved by the promotion as int and printf receives it as an int.
The format %02x expects an unsigned int value. printf was passed an int value, an incorrect type invoking undefined behavior. Since int and unsigned int use the same parameter passing convention on your platform, this negative value of -13 is interpreted as an unsigned int with the same bit pattern, with value 0xFFFFFFF3 because the int on your platform has 32 bits and negative values are represented in 2s complement. The string produced by printf is fffffff3. This behavior is not actually guaranteed by the C Standard.
In the second example, b[0] is an unsigned char with value 243 (0xf3). Its promotion to int preserves the value and the int passed to printf is 243. The same undefined behavior is invoked as printf is passed an int instead of an unsigned int. In your particular case, the conversion performed by printf yields the same value, which printed as hex with at least 2 digits padded with leading 0s gives f3.
To avoid this ambiguity, you should either cast the operand as unsigned char:
printf("%02x", (unsigned)(unsigned char)a[0]);
Or specify its actual type as unsigned char:
printf("%02hhx", (unsigned char)a[0]);
(Type char is signed, sizeof(int) is 4, 8 bits per byte.)
Both operands of a, are promoted to int, because of integer promotions:
a[0]^a[1];
Because a[1] is a signed type, char, the number 0xa5 actually represents a negative value of -91. The representation of the value -91 in type int is 0xffffffa5.
So the calculation becomes:
0x00000056 ^ 0xffffffa5
or in decimal:
86 ^ -91
The result is of that operation is:0xfffffff3
The unsigned char version of this calculations doesn't have this 'problem'.

why it shows like this in hexadecimal notation?

I'm trying to do bit arithmetic with variables a and b. When I reverse a, which has the value 0xAF, the result shows as 8 digits.
Unlike the others that show as 2 digits.
I don't know why it happens, but guess that it is relevant to %x's showing way and little endian?
Here is my code:
#include <stdio.h>
int main()
{
int a = 0xAF; // 10101111
int b = 0xB5; // 10110101
printf("%x \n", a & b); // a & b = 10100101
printf("%x \n", a | b); // a | b = 10111111
printf("%x \n", a ^ b); // a ^ b = 00011010
printf("%x \n", ~a); // ~a = 1....1 01010000
printf("%x \n", a << 2);// a << 2 = 1010111100
printf("%x \n", b >> 3); // b >> 3 = 00010110
return 0;
}
Considering your int a is most likely 32 bit in size, your a actually looks like this:
int a = 0xAF; // 0000 0000 0000 0000 0000 0000 1010 1111
So if you flip all the bits on that, you have
1111 1111 1111 1111 1111 1111 0101 0000
Or, in hex
0xFFFFFF50
Which is exactly what you're getting. The others show only 2 digits because trailing zeroes are omitted when printing hex, and your other bit operations do not in fact change any of the leading zeroes.
---- Credit to # chqrlie for this ----
If you really only want to see 8 bits of the result, you can do
printf("%hhx \n", ~a); // ~a = 1....1 01010000 --> Output : 50
Which restricts the printed value to unsigned char (8 bit [on modern os, not guaranteed, but very likely for your purposes]) length.
There's a lot of potential problems with code like this.
Most importantly, you should never use signed integer types like int when doing bitwise operations. Because you could either end up with unexpected results, or you could end up with undefined/implementation-defined behavior bugs if using operators like << >> on negative value integers.
So step one is to ensure you have an unsigned integer type. Preferably uint32_t or similar from stdint.h.
Another related problem is that if you use small integer types in an expression, such as uint8_t, char, short, bool etc, then they will get implicitly promoted to type int, which is a signed type. You get that even if you use unsigned char or uint8_t. This is the source of many fatal bugs related to the bitwise operators.
And finally, the printf family of functions is dangerous to use when you need to be explicit about types. While these function have literally zero type safety, they at the same time assume a certain, specific type. If you give them the wrong type you invoke undefined behavior and the program will potentially crash & burn. Also, being variable-argument list functions, they also use implicit promotion of the arguments (default argument promotions) which might also cause unforeseen bugs.
The "strange" output you experience is a combination of doing bitwise ~ on a signed type and printf expecting an unsigned int when you give it the %x conversion specifier.
In order to get more deterministic output, you could do something like this:
#include <stdio.h>
#include <inttypes.h>
int main()
{
uint32_t a = 0xAF; // 10101111
uint32_t b = 0xB5; // 10110101
printf("%.8" PRIx32 "\n", a & b); // a & b = 10100101
printf("%.8" PRIx32 "\n", a | b); // a | b = 10111111
printf("%.8" PRIx32 "\n", a ^ b); // a ^ b = 00011010
printf("%.8" PRIx32 "\n", ~a); // ~a = 1....1 01010000
printf("%.8" PRIx32 "\n", a << 2); // a << 2 = 1010111100
printf("%.8" PRIx32 "\n", b >> 3); // b >> 3 = 00010110
return 0;
}

What is the C equivalent for reinterpret_cast?

What is the C equivalent for the reinterpret_cast from C++?
int *foo;
float *bar;
// c++ style:
foo = reinterpret_cast< int * >(bar);
// c style:
foo = (int *)(bar);
If you can take the address of the value, one way is to cast a pointer to it to a pointer to a different type, and then dereference the pointer.
For example, an float-to-int conversion:
int main()
{
float f = 1.0f;
printf ("f is %f\n", f);
printf ("(int) f is %d\n", (int)f);
printf ("f as an unsigned int:%x\n", *(unsigned int *)&f);
}
Output:
f is 1.000000
(int) f is 1
f as an unsigned int:3f800000
Note that this is probably not guaranteed to work by the C standard. You cannot use reinterpret_cast to cast from float to int anyway, but it would be similar for a type that was supported (for example, between different pointer types).
Let's confirm the output above makes sense, anyway.
http://en.wikipedia.org/wiki/Single_precision_floating-point_format#IEEE_754_single-precision_binary_floating-point_format:_binary32
The last answer in binary:
0011 1111 1000 0000 0000 0000 0000 0000
This is IEEE-754 floating point format: a sign bit of 0, followed by an 8-bit exponent (011 1111 1), followed by a 23 bit mantissa (all zeroes).
To interpret the exponent, subtract 127: 01111111b = 127, and 127 - 127 = 0. The exponent is 0.
To interpret the mantissa, write it after 1 followed by a decimal point: 1.00000000000000000000000 (23 zeroes). This is 1 in decimal.
Hence the value represented by hex 3f800000 is 1 * 2^0 = 1, as we expected.
C-style casts just look like type names in parenthesis:
void *p = NULL;
int i = (int)p; // now i is most likely 0
Obviously there are better uses for casts than this, but that's the basic syntax.
It doesn't exist, because reinterpret_cast can not change [constness][3]. For example,
int main()
{
const unsigned int d = 5;
int *g=reinterpret_cast< int* >( &d );
(void)g;
}
will produce the error:
dk.cpp: In function 'int main()':
dk.cpp:5:41: error: reinterpret_cast from type 'const unsigned int*' to type 'int*' casts away qualifiers
A C-style cast is:
int* two = ...;
pointerToOne* one = (pointerToOne*)two;
What about a REINTERPRET operator for c:
#define REINTERPRET(new_type, var) ( * ( (new_type *) & var ) )
I don't like to say "reinterpret_cast", because cast means conversion (in c),
while reinterpret means the opposite: no conversion.
You can freely cast pointer types in C as you would any other type.
To be complete:
void *foo;
some_custom_t *bar;
other_custom_t *baz;
/* Initialization... */
foo = (void *)bar;
bar = (some_custom_t *)baz;
baz = (other_custom_t *)foo;

Resources