来自“The C Book”的第 1.1 节:
在最粗略的层面上,一个明显的特征是程序的多文件结构。该语言允许单独编译,其中完整程序的各个部分可以保存在一个或多个源文件中并相互独立编译。这个想法是编译过程将生成文件,然后可以使用系统提供的任何链接编辑器或加载器将这些文件链接在一起。类 Algol 语言的块结构通过坚持将整个程序放在一个块中而使这变得更加困难,尽管通常有绕过它的方法。
任何人都可以提供这种性质的编程的一些基本示例/概述吗?
来自“The C Book”的第 1.1 节:
在最粗略的层面上,一个明显的特征是程序的多文件结构。该语言允许单独编译,其中完整程序的各个部分可以保存在一个或多个源文件中并相互独立编译。这个想法是编译过程将生成文件,然后可以使用系统提供的任何链接编辑器或加载器将这些文件链接在一起。类 Algol 语言的块结构通过坚持将整个程序放在一个块中而使这变得更加困难,尽管通常有绕过它的方法。
任何人都可以提供这种性质的编程的一些基本示例/概述吗?
示例 Algol 程序,它没有任何用处,但在这里说明了这一点:
begin
int x; x:=3;
procedure p;
begin
integer y; y:=4;
procedure q(n);
value n; integer n;
if n > 0
then q(n-1)
else begin
integer z; z:=x+y;
print(z)
end;
q(1)
end;
p; comment a parameterless procedure call;
end;
这里的基本问题是嵌套范围。该过程q
取决于定义整数x
和的周围块y
。该过程p
同样取决于(通过包含q
)定义 的块x
。
然后,您会看到,这个愚蠢的示例程序的每个部分都与周围的文本密不可分。这是 Algolers 的自然表达方式;以对正在编写的程序有意义的方式嵌套过程。一般来说,这使得单独编译相当复杂。这与没有嵌套过程(函数等)的类 C 语言不同,因为它们可以引用的唯一非本地标识符是文件范围或全局范围(如果我的这些术语是正确的)。
在这里,变量x
和y
是某些过程的本地变量,因此位于堆栈上。只是为了让它更复杂,是递归的,它使得从最里面的调用到变量q
的位置的“堆栈下的距离” ,所以它不仅仅是从一些堆栈帧指针编译一个固定值的问题。x
y
然而,有些系统允许单独编译。据我记得,有一些限制,例如编译单元(如果你喜欢的话,一个文件)必须只包含“顶层”的过程。他们可能还需要一些扩展语法(如“外部过程 foo”)来告诉编译器不希望在当前文件中定义被引用的内容。
非单独编译的最小示例,单独文件m.c
包含:
int main() {}
编译:gcc m.c
生成可执行文件a.out
在 C 语言中,我们可以自由地将所有内容放在一个文件或多个文件中,也可以在一个或多个步骤中编译,如果这是您的问题
单独文件中有 2 个函数的示例m.c
:
#include <stdio.h>
void hw()
{
puts("hello world");
}
int main()
{
hw();
}
编译,我们也可以自由的一步一步来做
gcc m.c
生成可执行文件a.out
gcc -c m.c
产生m.o
然后gcc m.o
产生可执行文件a.out
使用多个文件的同一程序,hw.c
包含
#include <stdio.h>
#include "hw.h" /* not mandatory in current case but recommended to check signature compatibility */
void hw()
{
puts("hello world");
}
并hw.h
包含
#ifndef _HW_H
#define _Hw_H
extern void hw();
#endif
并m.c
包含
#include "hw.h"
int main()
{
hw();
}
编译,使用一个或多个步骤:
gcc m.c hw.c
生成可执行文件a.out
gcc -c m.c hw.c
产生对象m.o
,hw.o
然后gcc m.o hw.o
产生可执行文件a.out
gcc -c m.c
生成对象m.o
然后gcc -c hw.c
生成对象hw.o
然后gcc m.o hw.o
生成可执行文件a.out
也可以创建和使用一个库,这里是一个静态库,仅包含hw.o
:
gcc -c m.c hw.c
产生对象m.o
和hw.o
(或两个gcc命令,一个对象)ar rcs hw.a hw.o
使静态库包含hw.o
gcc m.o hw.a
生成可执行文件a.out
任何人都可以提供这种性质的编程的一些基本示例/概述吗?
调用add.c
一个包含以下代码的文件:
int add(int a, int b){
return a+b;
}
编译它:
gcc -c add.c
这会创建add.o
. 现在有一个包含以下代码的文件main.c
:
#include <stdio.h>
int add(int, int); // declares "add", but doesn't implement it!
int main( int argc, char **argv){
printf("3 + 2 = %d\n", add(3,2));
return 0;
}
这声明add
了,但没有实现它。它不会自行运行。但你仍然可以编译它
gcc -c main.c
然后你可以将它们链接到:
gcc add.o main.o
如果您运行生成的程序(可能称为 a.exe 或类似名称),您将获得以下结果:
3 + 2 = 5
这样做的好处是您可以修改其中一个部分,重新编译它,然后再次链接它,而无需触及其他部分。如果您想对此事进行更详细的解释,我建议您阅读此答案。
我不确定这本书的意思是“类 Algol 语言的块结构通过坚持将整个程序分成一个块来使这变得更加困难”。但我可以想象,一种类似 Algol 的语言允许或要求在主程序块中声明函数和过程,这意味着只有一个程序块,这将不允许像 C 那样将程序划分为可编译单元。但同样,我不知道这本书的意思是什么。
假设示例:
AlgolMain
Begin
procedure x
Begin
....
End
....
End