The following C code:
int main()
{
float f;
f = 3.0;
}
Is converted to the following assembly instructions:
main:
pushl %ebp
movl %esp, %ebp
subl $16, %esp
flds .LC0
fstps -4(%ebp)
movl $0, %eax
leave
ret
.LC0:
.long 1077936128
What is the correct way to calculate the .long
/int
representation of the float
literal?
e.g. 1077936128
generated from 3.0
for the example shown above
For this example
gcc
is used with the-m32 -S -O0 -fno-stack-protector -fno-asynchronous-unwind-tables
flags using intel settings to generate the assembly output.
References:
Compiler Explorer Link with compilation flags and other settings
x86 FPU hardware uses IEEE754 binary32 / binary64 representations for float
/ double
.
Determining the IEEE 754 representation of a floating point number is not trivial for humans. In handwritten assembly code, it's usually a good idea to use the .float
or .double
directives instead:
.float 3.0 # generates 3.0 as a 32 bit float
.double 3.0 # generates 3.0 as a 64 bit float
If you really want to compute this manually, refer to the explanations on Wikipedia. It might be interesting to do so as an exercise, but for actual programming it's tedious and mostly useless.
Compilers do the conversion (with rounding to the nearest representable FP value) internally, because FP values often don't come directly from a literal in the source; they can come from constant folding. e.g. 1.23 * 4.56
is evaluated at compile time, so the compiler already ends up with FP values in float or double binary representation. Printing them back to decimal for the assembler to parse and re-convert to binary would be slower and might require a lot of decimal places.
To compute the representation of a 32 bit float as a 32 bit integer, you can use an online IEEE754 converter, or a program like this:
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main(int argc, char *argv[])
{
union { uint32_t u32; float f32; } intfloat;
if (argc != 2) {
fprintf(stderr, "Usage: %s some-number\n", argv[0]);
return EXIT_FAILURE;
}
intfloat.f32 = atof(argv[1]);
printf("0x%08" PRIx32 "\n", intfloat.u32);
return EXIT_SUCCESS;
}