C89,混合变量声明和代码

我很好奇,当你尝试混合变量声明和代码时,为什么C89编译器会转储给你,例如:

rutski@imac:~$ cat test.c #include  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:~$ 

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

鉴于古老的C是多么的,我认为这个特征是由于一些历史问题可以追溯到70年代的非凡硬件限制,但我不知道细节。 或者我完全错了吗?

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

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

它可能从未以这种方式实现,因为它从未被需要。

假设你想在普通的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中,product仅在工厂工作时构造,即使这样,也会调用复制构造函数,而不是普通的构造函数和赋值运算符。

但是,我希望现在好的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(和其他语言)它并不是真的需要。

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

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

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

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

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