I was trying out few examples on do's and dont's of typecasting. I could not understand why the following code snippets failed to output the correct result.
/* int to float */
#include<stdio.h>
int main(){
int i = 37;
float f = *(float*)&i;
printf("\n %f \n",f);
return 0;
}
This prints 0.000000
/* float to short */
#include<stdio.h>
int main(){
float f = 7.0;
short s = *(float*)&f;
printf("\n s: %d \n",s);
return 0;
}
This prints 7
/* From double to char */
#include<stdio.h>
int main(){
double d = 3.14;
char ch = *(char*)&d;
printf("\n ch : %c \n",ch);
return 0;
}
This prints garbage
/* From short to double */
#include<stdio.h>
int main(){
short s = 45;
double d = *(double*)&s;
printf("\n d : %f \n",d);
return 0;
}
This prints 0.000000
Why does the cast from float to int give the correct result and all the other conversions give wrong results when type is cast explicitly?
I couldn't clearly understand why this typecasting of (float*) is needed instead of float
int i = 10;
float f = (float) i; // gives the correct op as : 10.000
But,
int i = 10;
float f = *(float*)&i; // gives a 0.0000
What is the difference between the above two type casts?
Why cant we use:
float f = (float**)&i;
float f = *(float*)&i;
In this example:
char ch = *(char*)&d;
You are not casting from double to a char. You are casting from a double* to a char*; that is, you are casting from a double pointer to a char pointer.
C will convert floating point types to integer types when casting the values, but since you are casting pointers to those values instead, there is no conversion done. You get garbage because floating point numbers are stored very differently from fixed point numbers.
Read about the representation of floating point numbers in systems. Its not the way you're expecting it to be. Cast made through (float *) in your first snippet read the most significant first 16 bits. And if your system is little endian, there will be always zeros in most significant bits if the value containing in the int type variable is lesser than 2^16.
If you need to convert int to float, the conversion is straight, because the promotion rules of C.
So, it is enough to write:
int i = 37;
float f = i;
This gives the result f == 37.0.
However, int the cast (float *)(&i), the result is an object of type "pointer to float".
In this case, the address of "pointer to integer" &i is the same as of the the "pointer to float" (float *)(&i). However, the object pointed by this last object is a float whose bits are the same as of the object i, which is an integer.
Now, the main point in this discussion is that the bit-representation of objects in memory is very different for integers and for floats.
A positive integer is represented in explicit form, as its binary mathematical expression dictates.
However, the floating point numbers have other representation, consisting of mantissa and exponent.
So, the bits of an object, when interpreted as an integer, have one meaning, but the same bits, interpreted as a float, have another very different meaning.
The better question is, why does it EVER work. You see, when you do
typedef int T;//replace with whatever
typedef double J;//replace with whatever
T s = 45;
J d = *(J*)(&s);
You are basically telling the compiler (get the T* address of s, reintepret what it points to as J, and then get that value). No casting of the value (changing the bytes) actually happens. Sometimes, by luck, this is the same (low value floats will have an exponential of 0, so the integer interpretation may be the same) but often times, this'll be garbage, or worse, if the sizes are not the same (like casting to double from char) you can read unallocated data (heap corruption (sometimes)!).
Related
I'm trying to interface a board with a raspberry.
I have to read/write value to the board via modbus, but I can't write floating point value like the board.
I'm using C, and Eclipse debug perspective to see the variable's value directly.
The board send me 0x46C35000 which should value 25'000 Dec but eclipse shows me 1.18720512e+009...
When I try on this website http://www.binaryconvert.com/convert_float.html?hexadecimal=46C35000 I obtain 25,000.
What's the problem?
For testing purposes I'm using this:
int main(){
while(1){ // To view easily the value in the debug perspective
float test = 0x46C35000;
printf("%f\n",test);
}
return 0;
}
Thanks!
When you do this:
float test = 0x46C35000;
You're setting the value to 0x46C35000 (decimal 1187205120), not the representation.
You can do what you want as follows:
union {
uint32_t i;
float f;
} u = { 0x46C35000 };
printf("f=%f\n", u.f);
This safely allows an unsigned 32-bit value to be interpreted as a float.
You’re confusing logical value and internal representation. Your assignments sets the value, which is thereafter 0x46C35000, i.e. 1187205120.
To set the internal representation of the floating point number you need to make a few assumptions about how floating point numbers are represented in memory. The assumptions on the website you’re using (IEEE 754, 32 bit) are fair on a general purpose computer though.
To change the internal representation, use memcpy to copy the raw bytes into the float:
// Ensure our assumptions are correct:
#if !defined(__STDC_IEC_559__) && !defined(__GCC_IEC_559)
# error Floating points might not be in IEEE 754/IEC 559 format!
#endif
_Static_assert(sizeof(float) == sizeof(uint32_t), "Floats are not 32 bit numbers");
float f;
uint32_t rep = 0x46C35000;
memcpy(&f, &rep, sizeof f);
printf("%f\n", f);
Output: 25000.000000.
(This requires the header stdint.h for uint32_t, and string.h for memcpy.)
The constant 0x46C35000 being assigned to a float will implicitly convert the int value 1187205120 into a float, rather than directly overlay the bits into the IEEE-754 floating point format.
I normally use a union for this sort of thing:
#include <stdio.h>
typedef union
{
float f;
uint32_t i;
} FU;
int main()
{
FU foo;
foo.f = 25000.0;
printf("%.8X\n", foo.i);
foo.i = 0x46C35000;
printf("%f\n", foo.f);
return 0;
}
Output:
46C35000
25000.000000
You can understand how data are represented in memory when you access them through their address:
#include <stdio.h>
int main()
{
float f25000; // totally unused, has exactly same size as `int'
int i = 0x46C35000; // put binary value of 0x46C35000 into `int' (4 bytes representation of integer)
float *faddr; // pointer (address) to float
faddr = (float*)&i; // put address of `i' into `faddr' so `faddr' points to `i' in memory
printf("f=%f\n", *faddr); // print value pointed bu `faddr'
return 0;
}
and the result:
$ gcc -of25000 f25000.c; ./f25000
f=25000.000000
What it does is:
put 0x46C35000 into int i
copy address of i into faddr, which is also address that points data in memory, in this case of float type
print value pointed by faddr; treat it as float type
you get your 25000.0.
wanna divide 2 numbers and get the result like this:
5 / 2 = 2.50
But it only outputs 2.
I don't now what i'm doing wrong.
Here my code:
int a;
int b;
int c;
printf("First num\n");
scanf("%d", &a);
printf("Second num\n");
scanf("%d", &b);
c = a / b;
printf("%d", c);
You need a double variable to store the result. int stores only integers. Additionally, you have to typecast the other variables also before performing the division.
Do something like this
double c;
.
.
.
c = (double)a / (double)b;
printf("%f", c);
NOTE:
You do not need the & in printf() statements.
To avoid the typecast in float you can directly use scanf with %f flag.
float a;
float b;
float c;
printf("First number\n");
scanf("%f", &a);
printf("Second number\n");
scanf("%f", &b);
c = a / b;
printf("%f", c);
The '/' - sign is for division. Whenever in C language, you divide an integer with an integer and store the data in an integer, the answer as output is an integer. For example
int a = 3, b = 2, c = 0;
c = a/b; // That is c = 3/2;
printf("%d", c);
The output received is: 1
The reason is the type of variable you have used, i.e. integer (int)
Whenever an integer is used for storing the output, the result will be stored as integer and not a decimal value.
For storing the decimal results, C language provide float, double, long float and long double.
Whenever you perform an operation and desires an output in decimal, then you can use the above mentioned datatypes for your resultant storage variable. For example
int a = 3, b = 2;
float c = 0.0;
c = (float)a/b; // That is c = 3/2;
printf("%.1f", c);
The output received: 1.5
So, I think this will help you to understand the concept.
Remember: When you are using float then the access specifier is %f. You need to convert your answer into float, just as I did, and then the answer will be reflected.
You have to use float or double variables, not int (integer) ones. Also note that a division between two integers will lead to an integer result, meanwhile a division between a float/double and an integer will lead to a float result. That's because C implicitly promote this integer to float.
For example:
5/2 = 2
5/2.0f = 2.5f
Note the .0f, this actually means that we are dividing with a float.
In C, only an int type number is displayed. 5/2 gives a floating point type number. So, the compiler compiles it only with the integer value.
What will be the output of the following C code?
Can the int data type take the floating-point values?
#include <stdio.h>
int main(){
float a = 1.1;
int b = 1.1;
if(a==b)
printf("YES");
else
printf("NO");
}
The output will be NO
It's because int can't store float values correctly. So, the value stored in b will be 1 which is not equal to 1.1. So, the if case will never be satisfied and thus the output will be NO always.
The value stored in b will be 1. When comparing, b will be cast to the float value 1.0f, so the comparison will yield NO.
int b = 1.1;
This truncates the double value 1.1 to 1 before assigning to variable b. The output therefore is NO.
But you can compare int to float. Consider this example:
float a=1.0;
int b=1;
if(a==b)
printf("YES");
else
printf("NO");
Here, a is converted to float before the comparison, and therefore you would get a YES output.
You should get the answer No when you execute it.
That's because when
int b=1.1;
was executed, it initialized a variable b and then assigned the int of 1.1 that is 1. You can check this by outputting the value of b.
Also the type int stores whole numbers only but float can store fractional numbers. The types are completely different.
It will compile without any errors. The output of the program will be "NO".
In C, int and float are 2 different data types. Even when you try to assign the value 1.1 to an integer variable in C, it will be initialized as 1 only.
Others already told you that the answer will be NO. Can the int data type take the floating-point values?
Yes they can, but only in one statement! IIf you want int variable to behave like float variable you need to cast it to float.
For example:
int x = 5;
int y = 3;
printf("%f \n", (float)x/y);
Output will be 5.0/3 and that would be float value. (float)x is called casting. You can also cast float value into integer, (int)some_var etc.
Note: Type of x and y will remain int! They only behave like float in this statement.
However, in your program that won't work, because as soon as you declare int b = 1.1; b becomes 1.
In C programming, I find a weird problem, which counters my intuition. When I declare a integer as the INT_MAX (2147483647, defined in the limits.h) and implicitly convert it to a float value, it works fine, i.e., the float value is same with the maximum integer. And then, I convert the float back to an integer, something interesting happens. The new integer becomes the minimum integer (-2147483648).
The source codes look as below:
int a = INT_MAX;
float b = a; // b is correct
int a_new = b; // a_new becomes INT_MIN
I am not sure what happens when the float number b is converted to the integer a_new. So, is there any reasonable solution to find the maximum value which can be switched forth and back between integer and float type?
PS: The value of INT_MAX - 100 works fine, but this is just an arbitrary workaround.
This answer assumes that float is an IEEE-754 single precision float encoded as 32-bits, and that an int is 32-bits. See this Wikipedia article for more information about IEEE-754.
Floating point numbers only have 24-bits of precision, compared with 32-bits for an int. Therefore int values from 0 to 16777215 have an exact representation as floating point numbers, but numbers greater than 16777215 do not necessarily have exact representations as floats. The following code demonstrates this fact (on systems that use IEEE-754).
for ( int a = 16777210; a < 16777224; a++ )
{
float b = a;
int c = b;
printf( "a=%d c=%d b=0x%08x\n", a, c, *((int*)&b) );
}
The expected output is
a=16777210 c=16777210 b=0x4b7ffffa
a=16777211 c=16777211 b=0x4b7ffffb
a=16777212 c=16777212 b=0x4b7ffffc
a=16777213 c=16777213 b=0x4b7ffffd
a=16777214 c=16777214 b=0x4b7ffffe
a=16777215 c=16777215 b=0x4b7fffff
a=16777216 c=16777216 b=0x4b800000
a=16777217 c=16777216 b=0x4b800000
a=16777218 c=16777218 b=0x4b800001
a=16777219 c=16777220 b=0x4b800002
a=16777220 c=16777220 b=0x4b800002
a=16777221 c=16777220 b=0x4b800002
a=16777222 c=16777222 b=0x4b800003
a=16777223 c=16777224 b=0x4b800004
Of interest here is that the float value 0x4b800002 is used to represent the three int values 16777219, 16777220, and 16777221, and thus converting 16777219 to a float and back to an int does not preserve the exact value of the int.
The two floating point values that are closest to INT_MAX are 2147483520 and 2147483648, which can be demonstrated with this code
for ( int a = 2147483520; a < 2147483647; a++ )
{
float b = a;
int c = b;
printf( "a=%d c=%d b=0x%08x\n", a, c, *((int*)&b) );
}
The interesting parts of the output are
a=2147483520 c=2147483520 b=0x4effffff
a=2147483521 c=2147483520 b=0x4effffff
...
a=2147483582 c=2147483520 b=0x4effffff
a=2147483583 c=2147483520 b=0x4effffff
a=2147483584 c=-2147483648 b=0x4f000000
a=2147483585 c=-2147483648 b=0x4f000000
...
a=2147483645 c=-2147483648 b=0x4f000000
a=2147483646 c=-2147483648 b=0x4f000000
Note that all 32-bit int values from 2147483584 to 2147483647 will be rounded up to a float value of 2147483648. The largest int value that will round down is 2147483583, which the same as (INT_MAX - 64) on a 32-bit system.
One might conclude therefore that numbers below (INT_MAX - 64) will safely convert from int to float and back to int. But that is only true on systems where the size of an int is 32-bits, and a float is encoded per IEEE-754.
So I have a program in C. its running but I don't understand how the output is generated ??
Here is the program :
#include <stdio.h>
int c;
void main() {
int a=10,b=20,j;
c=30;
int *p[3];
p[0]=&a;
p[1]=&b;
p[2]=&c;
j=p[0]-p[2];
printf("\nValue of p[0] = %u\nValue of p[2] = %u\nValue of j = %d\n\n",p[0],p[2],j);
}
and Here is the output :
Value of p[0] = 3213675396
Value of p[2] = 134520860
Value of j = -303953190
Can anyone tell me how j got this value i.e. -303953190 ?? It is supposed to be 3079154536
You are doing 3213675396 - 134520860. If you want to get the value use *p[0]. If your intention is to substract the address(which doesnt make sense but still) the expected answer should be 3079154536. But since the number if too large to hold hence you get the answer -303953190. Consider char for simplicity on number line
-128 -127 -126 -125 ... 0 1 2 ... 125 126 127
Now if you try to store 128 it out of range so it will give value -128. If try to assign value 130 you will get -126. So when the right hand side limit is exceeded you can see the counting starts from the left hand side. This is just for explanation purpose only the real reason for this behavior is owed due the fact that it is stored as two's compliment. More info can be found here
You should compute the difference of the pointed objects rather than of the pointers:
j=(*(p[0]))-(*(p[2]));
p is array of pointers to int - so its storing pointers to int and not ints. Hence, p[0] and p[2] are pointers - subtracting them will give you an integer which may overflow that you are trying to store in an int where the problem lies. Also addresses are to printed using %p not %d.
Dereference the value and you will get what you are looking for, like this:
j=p[0][0]-p[2][0];
or like this:
j=*(p[0])-*(p[2]);
Substracting two pointers results in a signed integer.
From the C Standard chapter 6.56:
6.5.6 Additive operators
[...]
9 When two pointers are subtracted, both shall point to elements of the same array object,
or one past the last element of the array object; the result is the difference of the
subscripts of the two array elements. The size of the result is implementation-defined,
and its type (a signed integer type) is ptrdiff_t defined in the < stddef.h> header.
And assigning the pointer difference to an int overflows the int.
To get around this overflow instead of
int j;
use
ptrdiff_t j;
and then print the value using %td.
From the C Standard chapter 7.17:
7.17 Common definitions < stddef.h>
[...]
2 The types are
ptrdiff_t
which is the signed integer type of the result of subtracting two pointers;
Also (unrelated)
void main()
is wrong. It shall be
int main(void)
So the correct code would look like this:
#include <stdio.h>
#include <stddef.h> /* for ptrdiff_t */
int c;
int main(void)
{
int a=10, b=20;
ptrdiff_t j;
int * p[3];
c=30;
p[0]=&a;
p[1]=&b;
p[2]=&c;
j=p[0]-p[2];
printf("\nValue of p[0] = %p\nValue of p[2] = %p\nValue of j = %td\n\n",
(void *) p[0],
(void *) p[2],
j);
return 0;
}
You're printing it as an integer instead of an unsigned. Use %u instead of %d.
Try this:
#include <stdio.h>
int c;
void main() {
int a=10,b=20;
unsigned j;
c=30;
int *p[3];
p[0]=&a;
p[1]=&b;
p[2]=&c;
j=(unsigned)p[0]-(unsigned)p[2];
printf("\nValue of p[0] = %u\nValue of p[2] = %u\nValue of j = %u\n\n",(unsigned)p[0],(unsigned)p[2],j);
}