非分开编译的例子?

时间:2019-02-25 08:40:53

标签: c compilation algol

摘自《 The C Book》第1.1节:

  

在最粗糙的层次上,一个明显的功能是多文件结构   一个程序。该语言允许单独编译,其中   完整程序的某些部分可以保存在一个或多个源文件中   并彼此独立地进行编译。这个想法是   编译过程将产生可以链接的文件   使用系统的任何链接编辑器或加载器一起   提供。类似Algol的语言的块结构使得   坚持要求整个程序合而为一,   尽管通常有一些解决方法。

有人能以这种方式提供一些基本的示例/编程概述吗?

4 个答案:

答案 0 :(得分:0)

非分开编译的最小示例,单独的文件m.c包含:

int main() {}

编译:{{1​​}}生成可执行文件gcc m.c


在C语言中,如果您有这样的问题,我们可以自由地将所有文件放入一个或多个文件中,也可以按一个或几个步骤进行编译

在单独的文件a.out中具有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.cm.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.cm.o(或两个 gcc 命令,每个对象一个)
  • hw.o来制作包含ar rcs hw.a hw.o的静态库
  • hw.o生成可执行文件gcc m.o hw.a

答案 1 :(得分:0)

  

任何人都可以提供一些基本示例/编程概述   这种性质?

有一个名为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

这样做的好处是,您可以修改其中一个部分,重新​​编译它,然后再次链接它,而无需接触其他部分。如果您希望对此问题进行更详细的说明,建议阅读this answer

答案 2 :(得分:0)

我不确定这本书对的含义是什么?“像Algol一样的语言的块结构通过坚持将整个程序放在一个块中而使这一工作变得更加困难。” 但我可以想象得到类似Algol的语言允许或要求在主程序块中声明函数和过程,这意味着仅存在一个程序块,这将不允许以C为单位将程序分区。但同样,我不知道这句话对本书的意义。

假设的例子:

AlgolMain
Begin
    procedure x
    Begin
        ....
    End
    ....
End

答案 3 :(得分:0)

示例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取决于定义整数xy的周围块。过程p同样(由于包含q)取决于定义x的块。

然后,您将看到这个愚蠢的示例程序的每个部分都与周围的文本密不可分。这是Algolers的自然表达方式;以对编写的程序有意义的方式嵌套过程。通常,这会使单独的编译变得非常复杂。这不同于没有嵌套过程(函数等)的类C语言,因为它们可以引用的唯一非本地标识符是文件范围或全局范围(如果我对这些术语正确的话)。

在这里,变量xy在某些过程中是局部的,因此位于堆栈中。为了使它更复杂,q是递归的,这使得从最内层调用到“ x”和“ y”位置的“向下堆栈距离”是可变的,因此不是只需从某个堆栈帧指针中编译一个固定值即可。

尽管如此,仍有一些系统允许单独编译。据我所知,存在一些限制,例如编译单元(如果需要,可以是一个文件)仅包含“顶层”过程。他们可能还需要一些扩展的语法(例如“ external procedure foo”),以告知编译器不应在当前文件中定义被引用的内容。