c++assemblycompiler-constructionfloating-point-conversion

What happens when I assign a float variable to an int variable in C++?


Let me start by saying that I don't know much about Assembly, but this is something that I'm wondering about.

Let's say that I have a code in C++ such as the following:

float f = 34.2;
int i;

i = f;

Now obviously what will happen when this code gets executed is that the value of f (34.2) will be converted to an integer value (34) and assigned to i.

My question is how does this conversion happens, I mean does it happen at runtime, so at runtime there is a code embedded into the executable that goes something like this: f is being assigned to i, now I know that f is a float and i is an integer, so what I should do is convert the bits in the f variable to an integer representation and then assign it to i;

Or what happens is that at compile time the i = f will directly be replaced by code that will convert a float to an integer?


Solution

  • Your code is

    float f = 34.2;
    int i;
    
    i = f;
    

    Just debug and have a look at the Dis-assembly Window. In a debug build (so constant-propagation doesn't happen, and the variables aren't optimized away entirely):

    float f = 34.2;
    01175498  movss       xmm0,dword ptr ds:[117DF70h]  
    011754A0  movss       dword ptr [f],xmm0  
    int i;
    
    i = f;
    011754A5  cvttss2si   eax,dword ptr [f]  
    011754AA  mov         dword ptr [i],eax  
    

    You can see the instruction cvttss2si (Convert with Truncation Scalar Single-Precision Floating-Point Value to Integer) is being executed.

    This is what Mats Petersson said in his comment. This instruction will convert the float to its integer representation, with rounding towards 0 regardless of the current rounding mode.

    The input operand is 32 bits wide, and is interpreted as IEEE single-precision because x86 uses that format for float.

    (C++ compilers targeting x86 without SSE1/SSE2 had to change the x87 rounding mode to truncation and then back to the previous value; that's why SSE1 and SSE2 included convert-with-truncation instructions but not other rounding-mode overrides, until SSE4.1 roundss/roundsd to implement floor/ceil/trunc/nearbyint with a floating-point result. C++ requires FP->integer conversions to truncate towards zero, separately from the default rounding mode when producing an FP result.)

    Most other modern ISAs have a single instruction FP->int conversion with truncation instruction, although non-CISC ones can only operate between registers and would need separate load and store in a debug build.