Dan*_*een 32 c compiler-construction language-design
在C编程语言中,我在使用任何非声明性/赋值表达式之前对所有语言修订都强制执行前面的变量声明.C++似乎已经放弃了所有版本的这一要求.我也认识到更多现代版本的C也放弃了这个要求,但我还没有使用任何这些标准.
我的问题是:有什么历史原因阻止C语言自由地按需而不是预先声明?
显然,从工程的角度来看,有许多原因可以解释,但对我来说,似乎没有任何一个理由可信.
有没有人有任何好的消息来支持上述任何一个?我完全错过了什么吗?我们可以推测从黎明到黄昏,但我正在寻找好的参考资料.
eca*_*mur 18
查看Dennis Ritchie主页的早期(第6版Unix,1975)C手册,在该版本中,函数 - 局部变量只能在函数的开头声明:
函数语句只是一个复合语句,可能在开始时有声明.
function-statement:{ declaration-list opt statement-list }
声明列表没有定义(省略),但可以很容易地假设有语法:
声明列表:声明 声明列表选择.
不允许其他复合语句包含变量(或实际上任何)声明.
这显然简化了实施; 在早期的编译器源代码中c02.c
,函数头函数blkhed()
只需要对auto
变量声明使用的堆栈空间求和,同时记录它们的堆栈偏移量,并发出代码以使堆栈指针碰撞适当的量.在函数退出(通过return
或结束),实现只需要恢复保存的堆栈指针.
事实上,K&R认为有必要声明"变量声明(包括初始化)可能在引入任何复合语句的左括号之后,而不仅仅是开始函数的语句 ",这一点暗示在那时它是一个相对较新的特征.它还表明组合声明初始化语法也是最近的一个特性,事实上在1975年手动声明器中不能有初始化器.
第11.1节中的1975手册明确指出:
C不是块结构语言; 这可能被认为是一个缺陷.
块语句和初始化声明(K&R)解决该缺陷,混合声明和代码(C99)是逻辑延续.
And*_*tin 10
在C89中,变量定义需要在块的开头.(参见块标定义的C标准)据我所知,这是为了简化汇编程序中变量的处理方式.例如,让我们看一个简单的函数:
void foo()
{
int i = 5;
printf("%i\n", i);
}
Run Code Online (Sandbox Code Playgroud)
当gcc将此函数转换为汇编代码时,对foo()的调用将归结为一堆指令,包括为函数范围设置堆栈帧.该堆栈帧包括在函数范围内定义的变量的空间,并且为了匹配更高级语言C中的相同范围,它们需要在块的开头定义.
最后,它是关于实现的简易性和效率,因为一次声明一堆变量,它在块的开头,使编译器能够在堆栈上批量推送它们,并且大约在89左右.这也是一个表现考虑因素.
当然,这个答案非常简单,只是为了简要说明为什么这样做已经完成了.有关更多信息,您可能应该阅读早期C89标准的一些草稿.
一个简短的答案并没有真正回答:C语言最初从其前身:B语言继承了这个声明顺序限制.为什么用B语言这样做我很遗憾,不知道.
另请注意,在新生C(在"C参考手册"中描述)中,使用非常量表达式初始化变量(甚至是本地变量)是非法的.
int a 5;
int b a; /* ERROR in nascent versions of C */
Run Code Online (Sandbox Code Playgroud)
(旁注:在CRM初始化语法中没有包含该=
字符).在一般情况下,这有效地否定了代码内变量声明的主要好处:能够将有意义的运行时值指定为初始化器.即使在更现代的C89/90中,这种限制仍然正式应用于聚合初始化器(尽管大多数编译器都忽略了它)
int a = 5, b = a;
struct { int x, y; } s = { a, b }; /* ERRROR even in C89/90 */
Run Code Online (Sandbox Code Playgroud)
只有在C99中才能使用运行时值进行各种本地初始化.这最终释放了代码内变量声明的全部功能,因此C99引入它们是完全合乎逻辑的.
归档时间: |
|
查看次数: |
1457 次 |
最近记录: |