C89,混合变量声明和代码

时间:2011-06-27 04:10:00

标签: c visual-c++ gcc c89

我非常好奇,当你尝试混合变量声明和代码时,为什么C89编译器会抛弃你,例如:

rutski@imac:~$ cat test.c
#include <stdio.h>

int
main(void)
{
    printf("Hello World!\n");
    int x = 7;
    printf("%d!\n", x);
    return 0;
}
rutski@imac:~$ gcc -std=c89 -pedantic test.c
test.c: In function ‘main’:
test.c:7: warning: ISO C90 forbids mixed declarations and code
rutski@imac:~$ 

是的,你可以通过远离愚蠢来避免这种事情。但是,您的代码不再符合标准。任何能够回答这篇文章的人都可能已经知道,这不仅仅是一个理论上的问题。像Microsoft的C编译器这样的平台在任何和所有情况下都可以在标准中快速执行。

考虑到古老的C是多少,我想这个功能是由于一些历史问题可以追溯到70年代的非凡硬件限制,但我不知道细节。或者我完全错了吗?

4 个答案:

答案 0 :(得分:7)

C标准说“你不应该”,因为在C89标准标准化的早期C编译器中不允许这样做。创建一种可用于编写操作系统及其实用程序的语言是一个足够激进的步骤。可能根本没有考虑这个概念 - 当时没有其他语言允许它(Pascal,Algol,PL / 1,Fortran,COBOL),所以C也不需要。并且它可能使编译器稍微难以处理(更大),并且原始编译器受到空间约束的64 KiB代码和PDP 11系列允许的64 KiB数据空间(大机器;仅较小的机器;代码和数据允许64 KiB,AFAIK)。因此,额外的复杂性并不是一个好主意。

C ++允许声明和变量交错,但C ++不是,而且从来没有C.但是,C99最终赶上了C ++(这是一个有用的功能)。可悲的是,微软从未实施过C99。

答案 1 :(得分:4)

可能从未实现过这种方式,因为它永远不需要。

假设你想在普通的C:

中写这样的东西
int myfunction(int value)
   {
   if (value==0)
      return 0;
   int result = value * 2;
   return result;
   }

然后你可以在有效的C中轻松地重写它,如下所示:

int myfunction(int value)
   {
   int result;
   if (value==0)
      return 0;
   result = value * 2;
   return result;
   }

首先声明变量,然后设置其值,绝对没有性能影响。

但是,在C ++中,情况不再如此。 在以下示例中,function2将比function1:

double function1(const Factory &factory)
   {
   if (!factory.isWorking())
      return 0;
   Product product(factory.makeProduct());
   return product.getQuantity();
   }

double function2(const Factory &factory)
   {
   Product product;
   if (!factory.isWorking())
      return 0;
   product = factory.makeProduct();
   return product.getQuantity();
   }

在function2中,即使工厂不工作,也需要构建产品变量。 之后,工厂生产产品,然后赋值操作员需要复制产品(从makeProduct的返回值到产品变量)。在function1中,只在工厂工作时才构造产品,即使这样,也会调用复制构造函数,而不是普通的构造函数和赋值运算符。

但是,我认为现在好的C ++编译器会优化这段代码,但在第一批C ++编译器中,情况可能并非如此。

第二个例子如下:

double function1(const Factory &factory)
   {
   if (!factory.isWorking())
      return 0;
   Product &product = factory.getProduct();
   return product.getQuantity();
   }

double function2(const Factory &factory)
   {
   Product &product;
   if (!factory.isWorking())
      return 0;
   product = factory.getProduct();    // Invalid.  You can't assign to a reference.
   return product.getQuantity();
   }

在此示例中,function2完全无效。引用只能在声明时分配一个值,而不能在以后分配。 这意味着在此示例中,编写有效代码的唯一方法是在实际初始化变量的时刻编写声明。不久。

这两个例子都说明了为什么在C ++中真正需要允许在其他可执行语句之后的变量声明,而不是像在C中一样在块的开头。 这就解释了为什么这个被添加到C ++中,而不是C(和其他语言),而不是真正需要它。

答案 2 :(得分:2)

它类似于要求在使用函数之前声明它们 - 它允许一个简单的编译器在一次传递中操作,从上到下,随着它发出目标代码。

在这种特殊情况下,编译器可以通过声明,累加所需的堆栈空间。当它到达第一个语句时,它可以输出代码来调整堆栈,为本地人分配空间,紧接在函数代码开始之前。

答案 3 :(得分:0)

为语言编写编译器要容易得多,这需要在函数的开头声明所有变量。有些语言甚至要求在函数代码之外的特定子句中声明变量(Pascal和Smalltalk会想到)。

原因是如果已知并且不更改,则将此变量映射到堆栈(或者如果编译器足够智能则将寄存器映射)更容易。

任何其他语句(尤其是函数调用)都可能修改堆栈/寄存器,使变量映射更复杂。