变量的类型被存储在哪里?它在哪里? 变量的类型保存在哪里?它在哪里?

4
例如,
float f = 2.4;
int n = f + 1;

n = 3

变量f在内存中的值为0x4019999a, 因此我认为f + 1 = 0x4019999a + 1, 但计算机并不这样认为。 如何知道f是“float”类型?即使f仅是内存中的0x4019999a。 变量类型是否存储在某个地方?


2
一旦编译器完成,类型就被有效地丢失了。它们可以通过检查编译器生成的汇编指令来推断,但类型本身并没有存储在任何地方。 - Some programmer dude
当编译器执行其任务时,它会在内部表中保留有关标识符类型的信息(该表不一定会输出到生成的二进制文件中)。使用 gcc,您可以尝试向二进制文件的生成添加调试选项 - pmg
2
计算机中的所有内容都是数字。这意味着从它的上下文中得出。在处理器级别,许多算术指令不知道一个数字是有符号还是无符号的,但程序员使用不同的标志来设置它。在您的示例中,编译器会生成适当的指令,因此数据类型是固有的。 - Weather Vane
编译器在内存中如何存储变量类型信息?C语言中的变量类型由谁来跟踪?编译器如何处理数据类型?类型信息存储在哪里,并且如何执行类型安全检查? - phuclv
这个回答解决了你的问题吗?编译器如何处理数据类型 - phuclv
我原本想创建一个TypeInfo引擎,它可以接受预处理输出并创建包含类型信息的文件。但如果您想要更简单的东西来完成您的项目,您可以使用宏来定义变量,例如: #define define(type, name) const char* name ## Type = #type; type name 并像这样使用:define(int, foo) = 5; printf("%s foo = %d", fooType, foo); - WENDYN
3个回答

5

在优化后的生产可执行文件中,类型并不会被显式地存储(调试输出包含各种额外信息)。

"那么如果类型没有被存储,它怎么知道如何处理f = f + 1n = n + 1这两个操作呢?" 我听到你在问。 :-) 答案是编译器在编译时知道了类型,并针对这些操作输出了不同的CPU指令。在f的情况下,它输出能够处理浮点数值的指令,但在n的情况下,它输出能够处理二进制补码整数的指令。


0

变量的类型不会被存储。编译器会根据你编写的代码发出相应的机器码指令。

以你的示例为例:

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

float类型的数值2.4被转换为int类型,其值为2。整数值2加上1,结果为3。在内存中,f的物理表示并不重要。

如果您想将f作为无符号整数的物理内存表示加上1,您需要:

float f = 2.4f;
unsigned n,m;

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

0

类型只在翻译时有影响,当编译器分析您的源代码并生成等效的机器代码时。这就是规则如“一元*的操作数必须具有指针类型”、“+的操作数必须具有算术类型”、“函数调用中的参数类型和数量必须与函数声明匹配”等被执行的时候。

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

所以我认为f + 1 = 0x4019999a + 1,但计算机并不这样认为。

int不能存储小数值 - 在C语言中的规则是,当您将浮点值分配给整数目标时,小数部分会被截断。 n无法存储3.4,它只能存储3

我采用了您上面的片段,并将其包装在一个完整的程序中,编译了它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的空间。该值加上%xmm01.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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接