C 编译的主要步骤是什么?

C 编译的主要步骤是什么?,c,gcc,assembly,compiler-construction,compilation,C,Gcc,Assembly,Compiler Construction,Compilation,编译C程序的主要步骤是什么?通过编译,我的意思是(可能是错误的)使用gcc从包含C代码的纯文本中获取二进制文件 我想了解该过程的一些关键点: 到一天结束时,我需要将我的C代码转换成一种我的CPU应该特别理解的语言。那么,谁在乎知道我的特定于CPU的指令呢?操作系统 gcc是否将任何C语言转换为汇编语言 我知道(实际上是猜测)对于每种处理器类型,我都需要一个汇编程序,它将解释(?)汇编代码并转换为我的CPU特定指令。这个装配工在哪里(谁运送它)?它随操作系统一起提供吗 如果我用文本编辑器打开二进制

编译C程序的主要步骤是什么?通过编译,我的意思是(可能是错误的)使用gcc从包含C代码的纯文本中获取二进制文件

我想了解该过程的一些关键点:

  • 到一天结束时,我需要将我的C代码转换成一种我的CPU应该特别理解的语言。那么,谁在乎知道我的特定于CPU的指令呢?操作系统

  • gcc是否将任何C语言转换为汇编语言

  • 我知道(实际上是猜测)对于每种处理器类型,我都需要一个汇编程序,它将解释(?)汇编代码并转换为我的CPU特定指令。这个装配工在哪里(谁运送它)?它随操作系统一起提供吗

  • 如果我用文本编辑器打开二进制文件,为什么我看不到0和1

  • 很多事情发生了:)

    以下是一些关键步骤(顺便说一句,这些是我对编译的看法,以下步骤仅与标准中定义的步骤有一点相似之处)

  • 预处理器在源文件上运行

    预处理器为我们做各种事情,包括:

    • 它执行三字形(特殊的三字符序列,代表早期键盘没有的一些特殊符号)替换
    • 它通过简单的文本替换执行宏替换(即
      #define
    • 它获取任何头文件,并将其全部内容复制到
      #include
      行所在的位置
    在Linux下,执行此操作的程序是
    m4
    ,使用
    gcc
    可以在执行此步骤后使用
    -E
    标志停止

  • 预处理器运行后,我们有一个文件,其中包含解析器运行和检查语法以及发出汇编所需的所有信息。在Linux下,最有可能执行此操作的程序是
    cc1
    ,使用
    gcc
    可以在执行此步骤后使用
    -s
    标志停止

  • 程序集很可能由程序
    gas
    (GNU Assembler)转换为目标代码,使用
    gcc
    ,您可以使用
    -c
    标志停止此步骤

  • 最后,链接器将一个或多个对象文件以及库转换为可执行文件。Linux下的链接器通常是
    ld
    ,使用
    gcc
    ,而不使用任何特殊标志


  • 由于您特别提到“在一天结束之前,我需要将我的C代码转换为我的CPU应该特别理解的语言”,因此我将解释一下编译器的工作原理

    典型的编译器做一些事情

    首先,他们做了一些叫做词法分析的事情。这一步将单个字符组合成“标记”,这是下一步理解的内容。这一步区分了语言关键字(如C中的“for”和“if”)、运算符(如“+”)、常量(如整数和字符串文字)以及其他内容。它的具体区别取决于语言本身

    下一步是解析器,它获取lexer生成的令牌流,并(通常)将其转换为称为“抽象语法树”或AST的内容。AST表示程序使用编译器可以导航的数据结构完成的计算。通常AST是独立于语言的,像GCC这样的编译器可以将不同的语言解析为下一步(代码生成器)可以理解的通用AST格式

    最后,代码生成器遍历AST并输出表示AST语义的代码,即实际执行AST表示的计算的代码

    对于GCC,可能还有其他编译器,编译器实际上并不生成机器代码。相反,它输出传递给汇编程序的汇编代码。汇编程序经过类似的词法分析、解析和代码生成过程来实际生成机器代码。毕竟,汇编程序只是编译汇编代码的编译器

    在C语言(和许多其他语言)的情况下,汇编程序通常不是最后一步。汇编程序生成称为对象文件的东西,其中包含对其他对象文件或库中函数的未解析引用(如C标准库中的printf或项目中其他C文件中的函数)。这些对象文件被传递给一个叫做“链接器”的东西,该链接器的任务是将所有对象文件合并成一个二进制文件,并解析对象文件中所有未解析的引用

    最后,完成所有这些步骤后,您就有了一个完整的可执行二进制文件

    请注意,这是GCC和许多其他编译器的工作方式,但不一定如此。您可以编写的任何程序都可以准确地接受一个C代码流,并输出一个等价的其他代码流(汇编、机器代码,甚至javascript),这就是编译器

    此外,这些步骤并不总是完全分开的。编译器不必对整个文件进行词法分析,然后解析整个结果,然后为整个AST生成代码,而是可以进行一些词法分析,然后在有一些标记时开始解析,然后在解析器需要更多标记时返回词法分析。当解析器觉得自己知道的足够多时,它可能会在让lexer为其生成更多标记之前进行一些代码生成

    在一天结束之前,我需要将我的C代码转换为我的CPU应该特别理解的语言。那么,谁在乎知道我的CPU特定指令呢?操作系统

    中央处理器

    <