2

I have the number 20 (0x14) stored in a 32-bit register. The register is allocated to a C float variable representing the value 2.8e-44. Now I want to get the hexadecimal representation of the float variable back and stored it into an integer variable in order to restore the original meaning of the information. Is there a better way to do that, apart from doing some pointer business? Here is the code:

#include <stdio.h>

int main()
{
    float f = 2.802597e-44;
    int nv,*pnv;
    printf("f=%f\n",f);
    printf("n=%d\n",f);
    nv=(int)f;
    printf("n=%d\n",nv);
    pnv=(int*)&f;
    printf("n=%d\n",(*pnv));
    return 0;
}

I get what I want using the pnv integer pointer. Is there a better way to do that avoiding pointers and working in C?

judoka_acl
  • 375
  • 2
  • 22
  • 1
    `float type register` what is that? – Sourav Ghosh Mar 21 '16 at 07:55
  • `printf("n=%d\n",f);` is UB. – Sourav Ghosh Mar 21 '16 at 07:56
  • 2
    Where do you have the value 20 in a variable of type float? I can only see a number close to 0 in `f`. – Jens Mar 21 '16 at 07:58
  • 1
    Do you (i) want to convert the `float` to an integer (i.e. preserve the numeric value as far as the conversion will allow), or do you want to treat the *memory* associated with the `float` *as* an integer? – Bathsheba Mar 21 '16 at 08:04
  • 1
    @Jens the hexadecimal representation of 2.8e-44 is 0x14. Check [link]http://www.h-schmidt.net/FloatConverter/IEEE754.html – judoka_acl Mar 21 '16 at 08:07
  • Apart from defining a union, your `pnv` logic is the usual way to do what you want to do. A small edit would be: `nv = *((int*)&f)`. Note that _avoiding pointers_ and _working in C_ are two exclusive propositions. – mouviciel Mar 21 '16 at 08:08
  • @mouviciel that version violates the strict aliasing rule – M.M Mar 21 '16 at 08:17
  • @mouviciel you are right, but this (*pnv) is used for array indexing, so I just want to get all possible alternatives. Could you make an answer with code for the union business? – judoka_acl Mar 21 '16 at 08:17
  • @M.M what is the strict aliasing rule? – judoka_acl Mar 21 '16 at 08:21
  • @lalamer http://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule – M.M Mar 21 '16 at 08:40

6 Answers6

5

You can achieve your need with a union:

#include <stdio.h>

int main()
{
  union { int i; float f; } fi;
  fi.f = 2.802597e-44;
  printf("f=%e\n",fi.f);
  printf("n=%d\n",fi.i);
  return 0;
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
mouviciel
  • 66,855
  • 13
  • 106
  • 140
2

Note that the behaviour of (int*)&f is undefined as the pointer types are unrelated. So don't approach the problem in that way.

Having checked that sizeof(float) is the same as sizeof(int), you could do this in one of two ways:

1) Type pruning through a union consisting of a float, and an int. Set the union using one member, and read it back with the other.

2) memcpy the contents of a variable of one type to the location of the variable of the other type.

Of these I prefer (2): (1) might be undefined with older C standards, and (2) also works well with C++.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • 1
    memcpy is actually the same thing, as the pointer stuff. Could you suggest a code example for the union trick just for completeness. You can mod my code. – judoka_acl Mar 21 '16 at 08:19
  • 1
    No, `memcpy` is *not* the same thing. `memcpy` is defined by the standard, your way of changing pointer types is *not*. – Bathsheba Mar 21 '16 at 08:28
  • defined by which standard? Provide references. – judoka_acl Mar 21 '16 at 08:31
  • @M.M thanks for the reference. I'm reading the ISO9899:1999 since I'm using a C99 compatible compiler. The 6.5.7 is named "Bitwise shift operators" and there is no memcpy mentioned. Have you meant something else? – judoka_acl Mar 21 '16 at 09:04
  • @Bathsheba: Though `memcpy` is defined by the standard, the interpretation of what is copied from a `float` to an `int` is not, just like the pointer logic. – mouviciel Mar 21 '16 at 09:04
  • @lalamer 6.5/7, not 6.5.7 – M.M Mar 21 '16 at 09:04
  • @M.M 6.5/7 on page 68? I don't see any references to memcpy there. There is one on 6.5/6 saying that "If a value is copied into an object having no declared type using memcpy or memmove, or is copied as an array of character type, then the effective type of the modified object for that access and for subsequent accesses that do not modify the value is the effective type of the object from which the value is copied, if it has one." Is that what you meant? – judoka_acl Mar 21 '16 at 09:07
  • No, 6.5/7. It starts off "An object shall have its stored value accessed only by an lvalue expression"... There is indeed no mention of `memcpy` there, we are talking about why `*(int *)&f` being undefined. The behaviour of `memcpy` is defined by C11 7.24.2.1 "The memcpy function" (numbering might differ in C99) from which it follows that the memcpy version is correct. – M.M Mar 21 '16 at 09:12
  • Why '*(int *)&f' is not an lvalue expression? – judoka_acl Mar 21 '16 at 09:25
  • Or what's the problem with it? – judoka_acl Mar 21 '16 at 09:27
1

You can directly cast it to integer as;

float a = 7.4;
int b = a; // this will be rounded to 7 and you will lose information

Or you can use some built-int functions like round, ceil, floor etc.

For reference: http://www.cplusplus.com/reference/cmath/round/?kw=round

zgrw
  • 127
  • 11
1

you can use type casting ..

float x =3.4;
int y = (int)x;
user
  • 143
  • 1
  • 8
0

What are you doing there is Undefined Behavior, didn't you check the warning?

warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘double’ [-Wformat=]
     printf("n=%d\n",f);
     ^

Read this please: How do the digits 1101004800 correspond with the number 20?

Community
  • 1
  • 1
gsamaras
  • 71,951
  • 46
  • 188
  • 305
  • http://www.h-schmidt.net/FloatConverter/IEEE754.html and check the Hexadecimal Representation, then convert 0x14 to decimal. – judoka_acl Mar 21 '16 at 08:04
  • @lalamer nice, see my updated answer please, thanks for the upvote, you got it too from me. – gsamaras Mar 21 '16 at 08:07
-2

C is considered a weakley typed langauge, which may allow to assign values that belong to different types than the variable they are being assigned with, therefore you can simply do this:

 int integer = 1;  
 float floater =1.1111;

 floater = integer;  

This is known as Implicit type conversion, also known as coercion, is an automatic type conversion by the compiler. Some programming languages allow compilers to provide coercion; others require it.

but consider the following:

  • what happens when the float is less than zero?
Aboudi
  • 308
  • 1
  • 2
  • 17