Copying data from float to an int, without the data being casted - c

In the following code I try to copy data from a float f to an int i, bit for bit, without any conversion of the data. I cast the address of f to (int*), and dereference this address when I assign it to i. The thinking is that if the program sees &f as an int pointer, it won't do a type conversion when (int*) f is dereferenced and assigned to i. But this isn't working and I do not understand why.
void main(){
float f=3.0;
int i;
/* Check to make sure int and float have the same size on my machine */
printf("sizeof(float)=%d\n",sizeof(float)); /* prints "sizeof(float)=4" */
printf("sizeof(int)=%d\n",sizeof(int)); /* prints "sizeof(int)=4" */
/* Verify that &f and (int*) &f have the same value */
printf("&f = %p\n",&f); /* prints &f = 0x7ffc0670dff8 */
printf("(int*) &f = %p\n",(int*) &f); /* prints (int*) &f = 0x7ffc0670dff8 */
i=*((int*) &f);
printf("%f\n", i); /* prints 0.000000 (I would have expected 3.000000) */
return;
}

By assigning via typecasting you are copying the raw 4 bytes of data from one variable to another. The problem is that a 3 in a 32-bit floating point variable isn't stored like a 3 in an integer variable.
For example, a 3 in 64-bit float format on a Mac is stored as 0x4e808000. Assigning that into an integer will produce 1077936128.
See https://en.wikipedia.org/wiki/IEEE_floating_point or http://www.madirish.net/240 or https://users.cs.duke.edu/~raw/cps104/TWFNotes/floating.html

Creating two pointers of unrelated types to the same object violates the strict aliasing rule. You want to avoid this, as in complicated code it can cause the compiler to produce binaries that don't do what you want. It's also undefined behaviour.
The correct way to change the type of a bit pattern in C between int and float is to avoid pointers completely, and use a union:
union int_float { int i; float f; };
int ival = (union int_float){ .f = 4.5 }.i;
float fval = (union int_float){ .i = 45 }.f;
Results may vary slightly. Be sure to check that the sizes of your floating type and your integer type are identical, or data will be lost/garbage data generated.
Note that it is possible to produce values in this way that are not valid elements of the destination type (this is more or less what you're seeing above when non-zero integer values get interpreted as floating-point zeroes despite not having all-zero bit patterns), which could lead to undefined or unexpected behaviour further down the line. Be sure to verify the output.

after the conversion you obtain an integer stored in the variable i.
So if you wannt to print such a value you have to use:
printf("%d\n", i); /* prints 1077936128 */
Now the printf will interprets correctly the memory bits and print the correct value.
This is not a cast but a bit copy like you said.
Remember that ((int)&f) dereference that pointer into an int value. It won't do what you believe on machines where int and float have different sizes.
A different way to copy, if the sizes of int and float are identical, is:
memcpy(&i, &f, sizeof f);
After copying the four bytes contained in the memory area if we try to print the content as a sequence of four decimal values we can appreciate the redistribution just happened:
for floating:
3 160 0 3
for integer
0 204 204 0
This means that the four bytes are managed differently from the computer according to the type of rapresentation: int or float.

Related

Size of a float variable and compilation

I'm struggling to understand the behavior of gcc in this. The size of a float is of 4 bytes for my architecture. But I can still store a 8 bytes real value in a float, and my compiler says nothing about it.
For example I have :
#include <stdio.h>
int main(int argc, char** argv){
float someFloatNumb = 0xFFFFFFFFFFFF;
printf("%i\n", sizeof(someFloatNumb));
printf("%f\n", someFloatNumb);
printf("%i\n", sizeof(281474976710656));
return 0;
}
I expected the compiler to insult me, or displaying a disclaimer of some sort, because I shouldn't be able to something like that, at least I think it's kind of twisted wizardry.
The program simply run :
4
281474976710656.000000
8
So, if I print the size of someFloatNumb, I get 4 bytes, which is expected. But the affected value isn't, as seen just below.
So I have a few questions:
Does sizeof(variable) simply get the variable type and return sizeof(type), which in this case would explain the result?
Does/Can gcc grow the capacity of a type? (managing multiple variables behind the curtains to allow us that sort of things)
1)
Does sizeof(variable) simply get the variable type and return sizeof(type), which in this case would explain the result ?
Except for variable-length arrays, sizeof doesn't evaluate its operand. So yes, all it cares is the type. So sizeof(someFloatNumb) is 4 which is equivalent to sizeof(float). This explains printf("%i\n", sizeof(someFloatNumb));.
2)
[..] But I can still store a 8 bytes real value in a float, and my compiler says nothing about it.
Does/Can gcc grow the capacity of a type ? (managing multiple variables behind the curtains to allow us that sort of things)
No. Capacity doesn't grow. You simply misunderstood how floats are represented/stored. sizeof(float) being 4 doesn't mean
it can't store more than 2^32 (assuming 1 byte == 8 bits). See Floating point representation.
What the maximum value of a float can represent is defined by the constant FLT_MAX (see <float.h>). sizeof(someFloatNumb) simply yields how many bytes the object (someFloatNumb) takes up in memory which isn't necessarily equal to the range of values it can represent.
This explains why printf("%f\n", someFloatNumb); prints the value as expected (and there's no automatic "capacity growth").
3)
printf("%i\n", sizeof(281474976710656));
This is slightly more involved. As said before in (1), sizeof only cares about the type here. But the type of 281474976710656 is not necessarily int.
The C standard defines the type of integer constants according to the smallest type that can represent the value. See https://stackoverflow.com/a/42115024/1275169 for an explanation.
On my system 281474976710656 can't be represented in an int and it's stored in a long int which is likely to be case on your system as well. So what you see is essentially equivalent to sizeof(long).
There's no portable way to determine the type of integer constants. But since you are using gcc, you could use a little trick with typeof:
typeof(281474976710656) x;
printf("%s", x); /* deliberately using '%s' to generate warning from gcc. */
generates:
warning: format ‘%s’ expects argument of type ‘char *’, but argument 2
has type ‘long int’ [-Wformat=]
printf("%s", x);
P.S: sizeof results a size_t for which the correct format specifier is %zu. So that's what you should be using in your 1st and 3rd printf statements.
This doesn't store "8 bytes" of data, that value gets converted to an integer by the compiler, then converted to a float for assignment:
float someFloatNumb = 0xFFFFFFFFFFFF; // 6 bytes of data
Since float can represent large values, this isn't a big deal, but you will lose a lot of precision if you're only using 32-bit floats. Notice there's a slight but important difference here:
float value = 281474976710656.000000;
int value = 281474976710655;
This is because float becomes an approximation when it runs out of precision.
Capacities don't "grow" for standard C types. You'll have to use a "bignum" library for that.
But I can still store a 8 bytes real value in a float, and my compiler
says nothing about it.
That's not what's happening.
float someFloatNumb = 0xFFFFFFFFFFFF;
0xFFFFFFFFFFFF is an integer constant. Its value, expressed in decimal, is 281474976710655, and its type is probably either long or long long. (Incidentally, that value can be stored in 48 bits, but most systems don't have a 48-bit integer type, so it will probably be stored in 64 bits, of which the high-order 16 bits will be zero.)
When you use an expression of one numeric type to initialize an object of a different numeric type, the value is converted. This conversion doesn't depend on the size of the source expression, only on its numeric value. For an integer-to-float conversion, the result is the closest representation to the integer value. There may be some loss of precision (and in this case, there is). Some compilers may have options to warn about loss of precision, but the conversion is perfectly valid so you probably won't get a warning by default.
Here's a small program to illustrate what's going on:
#include <stdio.h>
int main(void) {
long long ll = 0xFFFFFFFFFFFF;
float f = 0xFFFFFFFFFFFF;
printf("ll = %lld\n", ll);
printf("f = %f\n", f);
}
The output on my system is:
ll = 281474976710655
f = 281474976710656.000000
As you can see, the conversion has lost some precision. 281474976710656 is an exact power of two, and floating-point types generally can represent those exactly. There's a very small difference between the two values because you chose an integer value that's very close to one that can be represented exactly. If I change the value:
#include <stdio.h>
int main(void) {
long long ll = 0xEEEEEEEEEEEE;
float f = 0xEEEEEEEEEEEE;
printf("ll = %lld\n", ll);
printf("f = %f\n", f);
}
the apparent loss of precision is much larger:
ll = 262709978263278
f = 262709979381760.000000
0xFFFFFFFFFFFF == 281474976710655
If you init a float with that value, it will end up being
0xFFFFFFFFFFFF +1 == 0x1000000000000 == 281474976710656 == 1<<48
That fits easily in a 4byte float, simple mantisse, small exponent.
It does however NOT store the correct value (one lower) because that IS hard to store in a float.
Note that the " +1" does not imply incrementation. It ends up one higher because the representation can only get as close as off-by-one to the attempted value. You may consider that "rounding up to the next power of 2 mutliplied by whatever the mantisse can store". Mantisse, by the way, usually is interpreted as a fraction between 0 and 1.
Getting closer would indeed require the 48 bits of your initialisation in the mantisse; plus whatever number of bits would be used to store the exponent; and maybe a few more for other details.
Look at the value printed... 0xFFFF...FFFF is an odd value, but the value printed in your example is even. You are feeding the float variable with an int value that is converted to float. The conversion is loosing precision, as expected by the value used, which doesn't fit in the 23 bits reserved to the target variable mantissa. And finally you get an approximation with is the value 0x1000000....0000 (the next value, which is the closest value to the one you used, as posted #Yunnosch in his answer)

How to convert int array (holding float value in Hex) back into float value in C

I'm trying to write a automated test program that requires me to generate an int array datastream (which actually holds float data)
To generate that int array, i try to
write a floating number into char byte array, and then
convert the char byte array into an int array, which later
convert back the number from the int array to floating point ( without losing the decimal points).
I was able to do step 1 & 2 without issue, but I can't convert the int array back to floating point using ( float)(*int_ptr).
My code:
int ibuff[10];
int *int_ptr;
float f=0.1;
char c [sizeof(float)];
memcpy(c, &f, sizeof(float)); //now c is 0x3f800000;
ibuff[0]=(c[3]<<24 | c[2]<<16 | c[1]<<8 | c[0]); //ibuff[0] is now also 0x3f800000
int_ptr=&ibuff[0];
printf("%f\n", (float)(*int_ptr)); //this will print out 1065353216.0000, and not 1.0 as I expected
Your direct problem comes from casting the dereferenced integer pointer int_ptr to a float and then attempting to print that value as a float. You are currently attempting:
printf("%f\n", (float)(*int_ptr));
which as you have found will not work. What you want to do is interpret the value at the address held by int_ptr as a float. To accomplish that, you will need:
printf("%f\n", *(float*)(int_ptr));
While you can view the address as anything your like, you must make sure you do not run afoul of the strict-aliasing rules set forth in the C-standard at rules 6.5 (6) and 6.5 (7). There are limited exceptions specified, but as stated: "The intent ... is to specify those circumstances in which an object may or may not be aliased." Technically your cast from int to float is a violation which is masked by the use of a pointer (arrived at through the intervening use of a character array, which muddies the water a bit further).
In your print statement:
(float)(*int_ptr)
You are casting an int to a float, ie (float)(int)(x) will be the value of x as a float instead of an int. What you want is the memory of the location to be interperated as a float, so you need:
*(float *)(int_ptr)

C program : help about variable definition sequence

void main()
{
float x = 8.2;
int r = 6;
printf ( "%f" , r/4);
}
It is clearly odd that i am not explicitly typecasting the r ( of int type ) in the printf func to float. However if i change the sequence of declaring x and r and declare r first and then x i get different results(in this case it is a garbage value). Again i am not using x
in the program anywhere.. These are the things i meant to be wrong... i want to keep them the way they are. But when i excute the first piece of code i get 157286.375011 as result ( a garbage value ).
void main()
{
int r = 6;
float x = 8.2;
printf ( "%f" , r/4);
}
and if i execute the code above i get 0.000000 as result. i know results can go wrong because i am using %f in the printf when it should have been %d... the results may be wrong... but my question is why the results change when i change sequence of variable definitions. Should not it be the same whether right or wrong???
Why is this happening?
printf does not have any type checking. It relies on you to do that checking yourself, verifying that all of the types match the formatting specifiers.
If you don't do that, you enter into the realm of undefined behavior, where anything can happen. The printf function is trying to interpret the specified value in terms of the format specifier you used. And if they don't match, boom.
It's nonsense to specify %f for an int, but you already knew that...
f conversion specifier takes a double argument but you are passing an int argument. Passing an int argument to f conversion specifier is undefined behavior.
In this expression:
r / 4
both operands are of type int and the result is also of type int.
Here is what you want:
printf ("%f", r / 4.0);
When printf grabs the optional variables (i.e. the variables after the char * that tells it what to print), it has to get them off the stack. double is usually 64 bits (8 bytes) whereas int is 32 bits (4 bytes).
Moreover, floating point numbers have an odd internal structure as compared to integers.
Since you're passing an int in place of a double, printf is trying to get 8 bytes off the stack instead of four, and it's trying to interpret the bytes of a int as the bytes of a double.
So not only are you getting 4 bytes of memory containing no one knows what, but you're also interpreting that memory -- that's 4 bytes of int and 4 bytes of random stuff from nowhere -- as if it were a double.
So yeah, weird things are going to happen. When you re-compile (or even times re-run) a program that just wantonly picks things out of memory where it hasn't malloc'd and it hasn't stored, you're going to get unpredictable and wildly-changing values.
Don't do it.

Handling numbers in C

Couldnt understand how numbers are handled in C. Could anyone point to a good tutorial.
#include<stdio.h>
main()
{
printf("%f",16.0/3.0);
}
This code gave: 5.333333
But
#include<stdio.h>
main()
{
printf("%d",16.0/3.0);
}
Gave some garbage value: 1431655765
Then
#include<stdio.h>
main()
{
int num;
num=16.0/3.0;
printf("%d",num);
}
Gives: 5
Then
#include<stdio.h>
main()
{
float num;
num=16/3;
printf("%f",num);
}
Gives: 5.000000
printf is declared as
int printf(const char *format, ...);
the first arg (format) is string, and the rest can be anything. How the rest of the arguments will be used depending on the format specifiers in format. If you have:
printf("%d%c", x, y);
x will be treated as int, y will be treated as char.
So,
printf("%f",16.0/3.0);
is ok, since you ask for float double (%f), pass float double(16.0/3.0)
printf("%d",16.0/3.0);
you ask for int(%d), you pass float double (double and int have different internal representation) so, the bit representation of 16.0/3.0 (double) corresponds to bit representation of 1431655765(int).
int num;
num=16.0/3.0;
compiler knows that you are assigning to int, and converts it for you. Note that this is different than the previous case.
Ok, the first 1 is giving correct value as expected.
Second one you are passing a float while it is treating it as an int (hence the "%d" which is for displaying int datatypes, it is a little complicated to explain why and since it appears your just starting I wouldn't worry about why "%d" does this when passed a float) reading it wrong therefore giving you a wierd value. (not a garbage value though).
Third one it makes 16.0/3.0 an int while assigning it to the int datatype which will result in 5. Because while making the float an int it strips the decimals regardless of rounding.
In the fourth the right hand side (16/3) is treated as an int because you don't have the .0 zero at the end. It evaluates that then assigns 5 to float num. Thus explaining the output.
It is because the formatting strings you are choosing do not match the arguments you are passing. I suggest looking at the documentation on printf. If you have "%d" it expects an integer value, how that value is stored is irrelevant and likely machine dependent. If you have a "%f" it expects a floating point number, also likely machine dependent. If you do:
printf( "%f", <<integer>> );
the printf procedure will look for a floating point number where you have given an integer but it doesn't know its and integer it just looks for the appropriate number of bytes and assumes that you have put the correct things there.
16.0/3.0 is a float
int num = 16.0/3.0 is a float converted to an int
16/3 is an int
float num = 16/3 is an int converted to a float
You can search the web for printf documentation. One page is at http://linux.die.net/man/3/printf
You can understand numbers in C by using concept of Implecit Type Conversion.
During Evaluation of any Expression it adheres to very strict rules of type Conversion.
and your answer of expression is depends on this type conversion rules.
If the oparands are of different types ,the 'lower' type is automatically converted into the 'higher' type before the operation proceeds.
the result is of the higher type.
1:
All short and char are automatically converted to int then
2:
if one of the operands is int and the other is float, the int is converted into float because float is higher than an ** int**.
if you want more information about inplicit conversion you have to refer the book Programming in ANSI C by E Balagurusamy.
Thanks.
Bye:DeeP
printf formats a bit of memory into a human readable string. If you specify that the bit of memory should be considered a floating point number, you'll get the correct representation of a floating point number; however, if you specify that the bit of memory should be considered an integer and it is a floating point number, you'll get garbage.
printf("%d",16.0/3.0);
The result of 16.0/3.0 is 5.333333 which is represented in Single precision floating-point format as follows
0 | 10101010 | 10101010101010101010101
If you read it as 32bit integer value, the result would be 1431655765.
num=16.0/3.0;
is equivalent to num = (int)(16.0/3.0). This converts the result of float value(5.33333) to integer(5).
printf("%f",num);
is same as printf("%f",(float)num);

Weird result printing pointers as float in C

I know this is wrong and gcc will give you a warning about it, but why does it work (i.e. the numbers are printed correctly, with some rounding difference)?
int main() {
float *f = (float*) malloc(sizeof(float));
*f = 123.456;
printf("%f\n", *f);
printf("%f\n", f);
return 0;
}
Edit:
Yes, I'm using gcc with a 32-bit machine. I was curious to see what results I'd get with other compilers.
I meddled with things a little more following Christoph's suggestion:
int main() {
float *f = (float*) malloc(sizeof(float));
*f = 123.456;
printf("%f\n", f); // this
printf("%f\n", *f);
printf("%f\n", f); // that
return 0;
}
This results in the first printf printing a value different from the last printf, despite being identical.
Reorder the printf() statements and you'll see it won't work any longer, so GCC definetly doesn't fix anything behind your back.
As to why it works at all: Because of the default argument promotion of variable arguments, you'll actually pass a double with your first call. As pointers on your system seem to be 32bit, the second call only overwrites the lower half of the 64bit floating point value.
In regards to your modified example:
the first call will print a double precision value where the higher 32bits are garbage and the lower the bit value of the pointer f
the second call prints the value of *f promoted to double precision
the third call prints a double precision value with the higher 32bits coming from (double)*f (as these bits still remain on stack from the last call); as in the first case, the lower bits will again come from the pointer f
The numbers aren't printed correctly for me.
Output:
123.456001
0.000000
I'm using VC++ 2009.
printf has no knowledge about actual arguments type. It just analyzes format string and interprets data on stack accordingly.
By coincidence (more or less =)) pointer to float has the same size as float (32 bit) on your platform, so stack is balanced after removing this argument from it.
On other platforms or with other data types this may not work.

Resources