Type only matters during translation, when the compiler is analyzing your source code and generating the equivalent machine code. That's when rules like "the operand of unary *
must have pointer type" and "operands of +
must have arithmetic type" and "the type and number of parameters in a function call must match the function declaration" and so forth are enforced.
Type information is not explicitly stored in the generated machine code. Depending on the types used in the source code, the generated machine code will use different opcodes and registers based on the size of an object and whether or not it's floating point. On x86 for example, when adding two single precision floats together, the compiler will add the instruction addss
to the machine code; when adding two 32-bit int
s together, it will add the instruction addl
.
So I thought f + 1 = 0x4019999a + 1 but Computer doesn't.
An int
cannot store fractional values - the rule in C is that when you assign a floating-point value to an integer target, the fractional portion is truncated. n
cannot store 3.4
, it can only store 3
.
I took your snippet above and wrapped it in a complete program, compiled it1, then looked at the generated machine code. The lines
float f = 2.4;
int n = f + 1;
translate to the following:
movss LCPI0_0(%rip), %xmm0 ## xmm0 = mem[0],zero,zero,zero
movss LCPI0_1(%rip), %xmm1 ## xmm1 = mem[0],zero,zero,zero
...
movss %xmm1, -8(%rbp)
addss -8(%rbp), %xmm0
cvttss2si %xmm0, %eax
movl %eax, -12(%rbp)
The movss
instruction copies single-precision float values from one location to another - in this case, it's copying the floating point values 2.4
and 1.0
to the floating point registers %xmm0
and %xmm1
, respectively. The value in %xmm1
(2.4
) is copied to the location -8(%rpb)
, which is the space for the variable f
. That value is added to the value in %xmm0
(1.0
). At this point %xmm0
contains the value 3.4
. That value is then converted to its integer equivalent (3
) by the cvttss2si
instruction and the result is stored in 32-bit general purpose (i.e., non-floating point) register %eax
. That result is then copied to n
(-12(%rbp)
).
Remember that floating-point values and integer values have completely different representations. The binary representation of the 32-bit integer value 1
is 0x00000001
; the binary representation of the single-precision floating point value 1.0
is 0x3f800000
.
- Apple LLVM version 10.0.1 (clang-1001.0.46.4)
Target: x86_64-apple-darwin18.6.0