我最近成为了一门主要教授C语言的大学课程的助教。由于广泛的编译器支持,该课程标准化了C90.对于以前有Java经验的C语言新手来说,其中一个非常令人困惑的概念是变量声明和代码不能在块(复合语句)内混合。
这个限制在C99中终于被取消了,但我想知道:它最初存在的原因是什么?它简化了变量作用域分析吗?它允许程序员指定在程序执行的哪些点上堆栈应该为新变量增长吗?
我认为如果它绝对没有任何目的,语言设计者就不会添加这种限制。
我最近成为了一门主要教授C语言的大学课程的助教。由于广泛的编译器支持,该课程标准化了C90.对于以前有Java经验的C语言新手来说,其中一个非常令人困惑的概念是变量声明和代码不能在块(复合语句)内混合。
这个限制在C99中终于被取消了,但我想知道:它最初存在的原因是什么?它简化了变量作用域分析吗?它允许程序员指定在程序执行的哪些点上堆栈应该为新变量增长吗?
我认为如果它绝对没有任何目的,语言设计者就不会添加这种限制。
*.h
文件成为必需品。
- 在编译函数时,必须尽早计算堆栈帧的布局 - 否则编译器必须对函数体执行几次扫描。goto L1
+ L2: 函数主体代码
+ return
+ L1: stack_pointer -= size_of_locals
+ goto L2
。 - Alexey Frunze我认为对于一个非优化编译器来说,这种方式可以更容易地产生高效的代码:
int a;
int b;
int c;
...
尽管声明了3个不同的变量,但栈指针可以一次性增加,而无需优化策略(如重新排序等)。
与此相比:
int a;
foo();
int b;
bar();
int c;
要仅一次增加堆栈指针,这需要某种优化,尽管不是非常高级的优化。
此外,作为一种风格问题,第一种方法通过一次性查看所有本地变量并最终将它们作为一个整体检查,鼓励一种更有纪律的编码方式(难怪Pascal也强制执行此操作)。这提供了代码和数据之间更清晰的分离。
const
的唯一合理方法(例如,当值取决于在初始化新变量之前执行语句时)。如果您的所有变量都在块的开头声明,您就没有机会跟踪意外更改应该是常量的内容。 - Ruslan噢,但你可以(在某种程度上)混合声明和代码,但是声明新变量只限于块的开头。例如,以下是有效的C89代码:
void f()
{
int a;
do_something();
{
int b = do_something_else();
}
}