Display ieee 32bit representation of float ... strange behaviour on pointer output - c++

I have a bit of trouble with the following code:
void main()
{
float value = 100;
char * vP;
vP = (char *) &value;
printf ("%02x ", *(vP+3));
printf ("%02x ", *(vP+2));
printf ("%02x ", *(vP+1));
printf ("%02x ", *(vP+0));
}
The output I get is:
42 ffffffc8 00 00
instead of:
42 c8 00 00 (as required for an IEEE 32bit conversion)
Can anyone help and explain what goes wrong ? If I use
a float value of e.g. 12.2 everything is fine !
Thanks and best regards
Olaf.

That's because a char is signed on your machine. Then, in printf, because it's a variadic function, the char is promoted to an int keeping the negative sign. Therefore the 0xC8 becomes 0xFFFFFFC8.
Use an unsigned char* vP for force the representation to be unsigned. See http://www.ideone.com/WPQ4D for a comparison.

Related

C/C++ Printing bytes in hex, getting weird hex values

I am using the following to print out numbers from an array in hex:
char buff[1000];
// Populate array....
int i;
for(i = 0; i < 1000; ++i)
{
printf("[%d] %02x\n", i,buff[i]);
}
but I sometimes print weird values:
byte[280] 00
byte[281] 00
byte[282] 0a
byte[283] fffffff4 // Why is this a different length?
byte[284] 4e
byte[285] 66
byte[286] 0a
Why does this print 'fffffff4'?
Use %02hhx as the format string.
From CppReference, %02x accepts unsigned int. When you pass the arguments to printf(), which is a variadic function, buff[i] is automatically converted to int. Then the format specifier %02x makes printf() interprets the value as int, so potential negative values like (char)-1 get interpreted and printed as (int)-1, which is the cause of what you observed.
It can also be inferred that your platform has signed char type, and a 32-bit int type.
The length modifier hh will tell printf() to interpret whatever supplied as char type, so %hhx is the correct format specifier for unsigned char.
Alternatively, you can cast the data to unsigned char before printing. Like
printf("[%d] %02x\n", i, (unsigned char)buff[i]);
This can also prevent negative values from showing up as too long, as int can (almost) always contain unsigned char value.
See the following example:
#include <stdio.h>
int main(){
signed char a = +1, b = -1;
printf("%02x %02x %02hhx %02hhx\n", a, b, a, b);
return 0;
}
The output of the above program is:
01 ffffffff 01 ff
Your platform apparantly has signed char. On platforms where char is unsigned the output would be f4.
When calling a variadic function any integer argument smaller than int gets promoted to int.
A char value of f4 (-12 as a signed char) has the sign bit set, so when converted to int becomes fffffff4 (still -12 but now as a signed int) in your case.
%x02 causes printf to treat the argument as an unsigned int and will print it using at least 2 hexadecimal digits.
The output doesn't fit in 2 digits, so as many as are required are used.
Hence the output fffffff4.
To fix it, either declare your array unsigned char buff[1000]; or cast the argument:
printf("[%d] %02x\n", i, (unsigned char)buff[i]);

Why this comparison to zero is not working properly?

I have this code:
double A = doSomethingWonderful(); // same as doing A = 0;
if(A == 0)
{
fprintf(stderr,"A=%llx\n", A);
}
and this output:
A=7f35959a51c0
how is this possible?
I checked the value of 7f35959a51c0 and seems to be something like 6.91040329973658785751176861252E-310, which is very small, but not zero.
EDIT:
Ok I understood that that way of printing the hex value for a double is not working. I need to find a way to print the bytes of the double.
Following the comments I modified my code:
A = doSomethingWonderful();// same as doing A = 0;
if(A == 0)
{
char bytes[8];
memcpy(bytes, &A, sizeof(double));
for(int i = 0; i < 8; i++)
fprintf(stderr," %x", bytes[i]);
}
and I get this output:
0 0 0 0 0 0 0 0
So finally it seems that the comparison is working properly but I was doing a bad print.
IEEE 754 precision floating point values use a bias in the exponent value in order to fully represent both positive and negative exponents. For double-precision values, that bias is 1023[source], which happens to be 0x3ff in hex, which matches the hex value of A that you printed for 1, or 0e0.
Two other small notes:
When printing bytes, you can use %hhx to get it to only print 2 hex digits instead of sign-extending to 8.
You can use a union to reliably print the double value as an 8-byte integer.
double A = 0;
if(A == 0)
{
A = 1; // Note that you were setting A to 1 here!
char bytes[8];
memcpy(bytes, &A, sizeof(double));
for(int i = 0; i < 8; i++)
printf(" %hhx", bytes[i]);
}
int isZero;
union {
unsigned long i;
double d;
} u;
u.d = 0;
isZero = (u.d == 0.0);
printf("\n============\n");
printf("hex = %lx\nfloat = %f\nzero? %d\n", u.i, u.d, isZero);
Result:
0 0 0 0 0 0 f0 3f
============
hex = 0
float = 0.000000
zero? 1
So in the first line, we see that 1.0 is 0e0 (i.e., 00).
In the following lines, we see that when you use a union to print the hex value of the double 0.0, you get 0 as expected.
When you pass your double to printf(), you pass it as a floating point value. However, since the "%x" format is an integer format, your printf() implementation will try to read an integer argument. Due to this fundamental type mismatch, it is possible, for instance, that the calling code places your double value in a floating point register, while the printf() implementation tries to read it from an integer register. Details depend on your ABI, but apparently the bits that you see are not the bits that you passed. From a language point of view, you have undefined behavior the moment that you have a type mismatch between one printf() argument and its corresponding format specification.
Apart from that, +0.0 is indeed represented as all bits zero, both in single and in double precision formats. However, this is only positive zero, -0.0 is represented with the sign bit set.
In your last bit of code, you are inspecting the bit pattern of 1.0, because you overwrite the value of A before you do the conversion. Note also that you get fffffff0 instead of f0 for the seventh byte because of sign extension. For correct output, use an array of unsigned bytes.
The pattern that you are seeing decodes like this:
00 00 00 00 00 00 f0 3f
to big endian:
3f f0 00 00 00 00 00 00
decode fields:
sign: 0 (1 bit)
exponent: 01111111111 (11 bit), value = 1023
exponent = value - bias = 1023 - 1023 = 0
mantissa: 0...0 (52 bit), value with implicit leading 1 bit: 1.0000...
entire value: -1^0 * 2^0 * 1.0 = 1.0

Code to find Endianness-pointer typecasting

I was trying to search for a code to determine the endianness of the system, and this is what I found:
int main()
{
unsigned int i= 1;
char *c = (char *)&i;
if (*c) {
printf("Little Endian\n");
} else {
printf("Big Endian\n");
}
}
Could someone tell me how this code works? More specifically, why is the ampersand needed here in this typecasting :
char *c = (char *)&i;
What is getting stored into the pointer c.. the value i contains or the actual address i is contained in? Also why is this a char for this program?
While dereferencing a character pointer, only one byte is interpreted(Assuming a char variable takes one byte).And in little-endian mode,the least-significant-byte of an integer is stored first.So for a 4-byte integer,say 3,it is stored as
00000011 00000000 00000000 00000000
while for big-endian mode it is stored as:
00000000 00000000 00000000 00000011
So in the first case, the char* interprets the first byte and displays 3 but in the second case it displays 0.
Had you not typecasted it as :
char *c = (char *)&i;
it will show a warning about incompatible pointer type.Had c been an integer pointer, dereferencing it will get an integer value 3 irrespective of the endianness,as all 4 bytes will be interpreted.
NB You need to initialize the variable i to see the whole picture.Else a garbage value is stored in the variable by default.
Warning!! OP,we discussed the difference between little-endian and big-endian,but it's more important to know the difference between little-endian and little-indian.I noticed that you used the latter.Well, the difference is that little-indian can cost you your dream job in Google or a $3 million in venture capital if your interviewer is a Nikesh Arora,Sundar Pichai,Vinod Dham or Vinod Khosla :-)
Let's try to walk through this: (in comments)
int main(void){ /
unsigned int i = 1; // i is an int in memory that can be conceptualized as
// int[0x00 00 00 01]
char *c = *(char *)&i; // We take the address of i and then cast it to a char pointer
// which we then dereference. This cast from int(4 bytes)
// to char(1 byte) results in only keeping the lowest byte by
if(*c){ // Endian-ness.
puts("little!\n"); // This means that on a Little Endian machine, 0x01 will be
} else { // the byte kept, but on a Big Endian machine, 0x00 is kept.
puts("big!\n"); // int[0x00 00 00 (char)[01]] vs int[0x01 00 00 (char)[00]]
}
return 0;
}

Unexpected behavior from unsigned_int64;

unsigned__int64 difference;
difference=(64*33554432);
printf ("size %I64u \n", difference);
difference=(63*33554432);
printf ("size %I64u \n", difference);
the first # is ridiculously large. The second number is the correct answer. How does changing it from 62 to 63 cause such a change?
First value is 18446744071562067968
Second value is 2113929216
Sorry the values were 64 and 63, not 63 and 62.
Unless qualified otherwise, integer literals are of type int. I would assume that on the platform you're on, an int is 32-bit. So the calculation (64*33554432) overflows and becomes negative. You then cast this to a unsigned __int64, so this now gets flipped back to a very very large positive integer.
Voila:
int main()
{
int a1 = (64*33554432);
int a2 = (63*33554432);
printf("%08x\n", a1); // 80000000 (negative)
printf("%08x\n", a2); // 7e000000 (positive)
unsigned __int64 b1 = a1;
unsigned __int64 b2 = a2;
printf("%016llx\n", b1); // ffffffff80000000
printf("%016llx\n", b2); // 000000007e000000
}
On gcc it works fine and gives out the correct number in both cases.
size 2113929216
size 2080374784
Could it be a bug with printf?
Are you using MSVC or similar? try stepping it through the debugger and inspect difference after each evaluation. If the numbers look right there then it might just be a printf problem. However, under gcc on linux it's correct.

Infinity in MSVC++

I'm using MSVC++, and I want to use the special value INFINITY in my code.
What's the byte pattern or constant to use in MSVC++ for infinity?
Why does 1.0f/0.0f appear to have the value 0?
#include <stdio.h>
#include <limits.h>
int main()
{
float zero = 0.0f ;
float inf = 1.0f/zero ;
printf( "%f\n", inf ) ; // 1.#INF00
printf( "%x\n", inf ) ; // why is this 0?
printf( "%f\n", zero ) ; // 0.000000
printf( "%x\n", zero ) ; // 0
}
Use numeric_limits:
#include <limits>
float maxFloat = std::numeric_limits<float>::infinity();
printf("%x\n", inf) expects an integer (32 bit on MSVC), but receives a double. Hilarity will ensue. Err, I mean: undefined behavior.
(And yes, it receives a double since for a variable argument list, floats are promoted to double).
Edit anyways, you should use numeric_limits, as the other reply says, too.
In the variable arguments list to printf, floats get promoted to doubles. The little-endian byte representation of infinity as a double is 00 00 00 00 00 00 F0 7F.
As peterchen mentioned, "%x" expects an int, not a double. So printf looks at only the first sizeof(int) bytes of the argument. No version of MSVC++ defines int to be larger than 4 bytes, so you get all zeros.
Take a look at numeric_limits::infinity.
That's what happens when you lie to printf(), it gets it wrong. When you use the %x format specifier, it expects an integer to be passed on the stack, not a float passed on the FPU stack. Fix:
printf( "%x\n", *(__int32*)&inf ) ;
You can get infinity out of the <limits> C++ header file:
float inf = std::numeric_limits<float>::infinity().