变量的类型是否存储在某处?它在哪里?

Is the type of variable stored somewhere? Where is it?

例如,

float f = 2.4;
int n = f + 1;

n = 3

变量f在内存中是0x4019999a, 所以我想 f + 1 = 0x4019999a + 1 但计算机没有。 如何知道 f 是 'float'?即使 f 在内存中只是 0x4019999a。 变量的类型是否存储在某处?

type 未显式存储(在优化的生产可执行文件中;调试输出中包含各种额外信息)。

“所以如果类型没有存储,它如何知道如何以不同于 n = n + 1 的方式处理 f = f + 1?”我听到你问。 :-) 答案是编译器在编译时知道类型,并且它为这些操作输出不同的 CPU 指令。在 f 的情况下,它输出使用浮点值的指令,但在 n 的情况下,它输出使用二进制补码整数的指令。

不存储变量类型。编译器根据您编写的代码发出机器码指令。

在你的例子中:

float f = 2.4;
int n = f + 1;

float2.4 正在转换为 int,其值为 21 与整数值 2 相加。结果是3f 在内存中的物理表示无关紧要。

如果要将 1 添加到 f 的物理内存表示中,将其视为无符号整数,您需要:

float f = 2.4f;
unsigned n,m;

memcpy(&n, &f, sizeof(n));
m = n + 1;

Type 仅在翻译期间很重要,此时编译器正在分析您的源代码并生成等效的机器代码。这就是像“一元 * 的操作数必须具有指针类型”和“+ 的操作数必须具有算术类型”和“函数调用中参数的类型和数量必须与函数声明匹配”等规则"等等都是强制执行的。

类型信息未明确存储在生成的机器代码中。根据源代码中使用的类型,生成的机器代码将根据对象的大小以及它是否为浮点数使用不同的操作码和寄存器。例如,在 x86 上,当将两个单精度浮点数相加时,编译器会将指令 addss 添加到机器代码中;两个32位的int相加时,会加上指令addl.

So I thought f + 1 = 0x4019999a + 1 but Computer doesn't.

int 不能存储小数值 - C 中的规则是,当您将浮点值分配给整数目标时,小数部分会被截断。 n不能存3.4,只能存[=2​​0=].

我把你上面的代码片段打包成一个完整的程序,编译它1,然后查看生成的机器代码。线条

float f = 2.4;
int n = f + 1;

翻译如下:

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)

movss 指令将单精度浮点值从一个位置复制到另一个位置 - 在本例中,它将浮点值 2.41.0 复制到浮点寄存器分别为 %xmm0%xmm1%xmm1 (2.4) 中的值被复制到位置 -8(%rpb),即变量 f 的 space。该值将添加到 %xmm0 (1.0) 中的值。此时 %xmm0 包含值 3.4。然后,cvttss2si 指令将该值转换为其等效整数 (3),并将结果存储在 32 位通用(即非浮点数)寄存器 %eax 中。然后将该结果复制到 n (-12(%rbp)).

请记住,浮点值和整数值具有完全不同的 表示形式。 32位整数值1的二进制表示为0x00000001;单精度浮点值 1.0 的二进制表示是 0x3f800000.


  1. Apple LLVM 版本 10.0.1 (clang-1001.0.46.4)
    目标:x86_64-apple-darwin18.6.0