数据类型何时意味着比编译器的存储空间更多?

时间:2015-01-17 04:41:45

标签: c++ c types type-conversion

说我有以下变量声明:

float f = 23.4;

现在这意味着两件事(可能更多?):

  1. 它告诉编译器在内存中分配4个字节的存储空间。
  2. 它告诉编译器将此4字节存储中包含的位视为实数。
  3. 现在我的问题是编译器将f何时被视为实数而不仅仅是4字节的存储空间?我可以想到以下场景:

    1. 当我为其分配一个数字(例如23.4)时,编译器会将此数字转换为表示实数的相应位,并将其放入f
    2. 当我为其分配int变量时,int变量将被转换(转换)为代表实数的位并放入f(即使这意味着数据)失利)。或者当我尝试为其分配不允许的数据类型(例如struct)时,编译器会抱怨。
    3. 当我在算术运算中使用它作为操作数时,例如i + f,编译器会知道ffloatiint 1}}所以不只是将fi中包含的位一起添加,而是添加这些位代表的内容。
    4. 但是,例如,当我想将f输出到控制台时,编译器与它无关。因此,当我使用printf()时,我会告诉printf() f代表什么(通过指定%f参数)。或者当我想从控制台读取输入时,我也告诉scanf()我想将用户接收的字节转换为实数(通过指定%f参数)。< / p>

      那么编译器是否负责解释变量内容的其他场景呢?

3 个答案:

答案 0 :(得分:2)

您最终会询问编译器的工作原理以及它们如何处理类型信息和数据表示。这里的答案很广泛,有多种方法:

某些编译器执行类型擦除,因此没有关于特定变量在内存中的类型的信息。当您调用printf时,编译器如何知道它应如何处理数据?好吧,因为你告诉它类型。展示类型擦除的编译器确保对于任何变量,所有类型在编译时都是已知的,因此在将更高级别的程序转换为机器语言时,例如,将两个变量一起添加,它知道是执行整数加法还是浮动点加法,因为它知道所涉及的变量的类型。它也可以知道它应该如何传递要打印的变量等。

另一方面,一些解释器和托管编译器不会显示类型擦除。相反,这些编译器将代码变量的代码编码为变量本身的一部分。这允许解释器在运行时检查变量是什么,必要时进行转换,并决定对其执行哪些操作。


请注意,整数和单精度浮点数在内存中的表示方式非常不同(尽管在大多数语言和体系结构中两者都占用4个字节)。要知道如何显示或添加内容,编译器需要知道它是什么类型。编译器可以发出在运行时决定的代码(一些托管程序),或者解释器可以决定在运行时如何处理它,或者编译器可能需要知道编译时每个变量是什么,从而消除了需要在运行时存储并指定内存中的类型。


在C中,printf是语言表明它不是完全类型安全的区域之一(它最初让我感到困惑的是为什么有人会说C类型不安全,当它显然有类型和似乎是强类型的。)

请注意,在C ++中,使用std::cout,您可以输出intdoublestd::string等,而无需告诉编译器您输出的是什么。这是因为对于std::cout,C ++编译器将在编译时找出变量的类型并调用适当的<<重载,该重载正确地格式化表示变量的内存块,或者作为一个intdoublestd::string或其他任何内容。

对于printf,该函数的规范旨在接受一堆&#34;数据&#34; 并打印出来。我确信有这样的有趣和历史原因。最明显的一点是变量长度参数不能用多种类型描述,因此传递给printf的参数是某些&#34; any&#34;类型..但是在编译函数体时,编译器知道传递了可变数量的参数,但不知道每个参数的类型。

如果你为printf提供了几十个重载,其中包含了不同可能类型的每种组合和排列,长达一定长度,那么你就可以避免暗示程序类型是什么运行时。

答案 1 :(得分:1)

严格来说,我认为这不是你问题的答案,而是听起来像是你误解了一些东西。

首先,您的假设中存在一些错误:

  • float变量的声明并不告诉编译器在内存中分配4个字节的存储空间&#34;。它告诉编译器分配一个float,但是它是在内存中,在寄存器中,完全隐式地分配(没有真正的存储),或者,可以想象,以某种完全不同的方式分配直到编译器。对于所有C规范的关注,编译器可以使用您的声卡将float存储在扬声器和麦克风之间的音频延迟环路中。
  • 即使您将float传递给printf(),编译器也会非常投入。您可能已经意识到它只是将四个字节复制到堆栈上,但这仅仅是x86 ABI的巧合。即使在AMD64上,这也不是真的,并且varargs函数的float参数将在SSE寄存器中传递(而不是在整数GPR中传递的int参数,因此编译器非常很有意义。)

当然,编译器不会告诉printf()获取float来打印它,但是这个责任在于你,但这不是因为编译器&# 34;忽略&#34; float变量的内容,而仅仅是因为没有传递给函数的运行时类型信息,因此printf()需要有关从调用帧中获取什么类型值的信息。或者,换句话说,即使编译器知道值的数据类型并相应地调整生成的代码以匹配ABI和所有内容,它也没有义务告诉printf()它传递给它的是什么,因此你需要告诉printf()它的位置。

从这个角度来看,回答你的问题,数据类型总是意味着不仅仅是编译器的存储大小,但我觉得你想问的实际问题是别的。

答案 2 :(得分:-3)

请检查http://en.wikipedia.org/wiki/Double-precision_floating-point_format

它只是一个4字节的存储空间。

整个CPU浮点运算基于编译器产生正确的指令集并了解数据类型,

当然你可以分配4个字节的存储空间,把它伪装成实数(强制转换),但这只相当于用脚射击自己。