c++ primer 题解 2020.12.28

513 阅读2分钟

1.1查阅你使用的编译器的文档,确定它所使用的文件命名约定。编译并运行第2页的main程序

gcc 文件名约定:

文件名+扩展名GCC 编译器识别的文件类型
file.c尚未经过预处理操作的 C 源程序文件
file.i经过预处理操作、但尚未进行编译、汇编和连接的 C 源代码文件
file.cpp
file.cp
file.cc
file.cxx
file.CPP
file.c++
file.C
尚未经过预处理操作的 C++ 源代码文件。
file.ii已经预处理操作,但尚未进行编译、汇编和连接的 C++ 源代码文件
file.s经过编译生成的汇编代码文件
file.hC、C++ 或者 Objective-C++ 语言头文件
file.hh
file.H
file.hp
file.hxx
file.hpp
file.HPP
file.h++
file.tcc
C++ 头文件。

g++ 编译过程

运行环境 macOS Catalina 10.15.7

$ uname -sr
Darwin 19.6.0

g++版本

$ g++ --version
  Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-	dir=/Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/usr/include/c++/4.2.1
  Apple clang version 12.0.0 (clang-1200.0.32.28)
  Target: x86_64-apple-darwin19.6.0
  Thread model: posix
  InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

源文件 main.cpp

#include <iostream>

int main(int argc, char *argv[]) {
    std::cout << "Hello world" << std::endl;
    return 0;
}

c++的编译过程分为四个部分

预处理 --> 编译 --> 汇编 --> 链接

compilation

1、预处理

  • 宏定义展开,并将#define删除
  • 处理条件编译,如#ifdef,#ifndef,#elif,#else,#endif等,过滤不必要的代码
  • 处理#include预编译指令,将包含的文件插入到该预编译指令的位置,该过程递归进行,因为被包含的文件也可能包含其他文件
  • 过滤注释,如/**/和//里的内容
  • 添加行号和文件名标识
  • 保留#pragma编译指令,待后续编译器使用
$ g++ -E ./main.cpp -o main.i   # 执行预处理

生成文件如下:

image-20201228161350546
$ wc -l ./main.i # 查看文件行数
	43927 ./main.i

由于执行了头文件展开,插入了#include所包的文件的内容,因此预处理文件行数远多于源文件

2、编译

  • 将预处理文件进行一系列词法分析,语法分析,语义分析,以及优化后产生相应的汇编代码文件,这个过程是程序构建的核心部分,也是最复杂的。
$ g++ -S ./main.i -o ./main.s # 编译文件

生成文件如下:

image-20201228161531949

3、汇编

  • 汇编过程指的是把汇编语言代码翻译成目标机器指令的过程,即生成目标文件。对于被翻译系统处理的每一个c语言源程序,都将最终经过这一处理而得到相应的目标文件。目标文件中所存放的也就是与源程序等效的机器代码。目标文件由段组成,通常一个目标文件中至少有两个段:

    • 代码段,包含程序指令,一般可以读取并执行,且无法修改
    • 数据段,主要存放全局变量和静态变量,数据段一般可读可写
  • UNIX环境下主要有三种类型的目标文件:

    • 可重定位文件:其中包含有适合于其它目标文件链接来创建一个可执行的或者共享的目标文件的代码和数据。
    • 共享的目标文件:这种文件存放了适合于在两种上下文里链接的代码和数据。第一种事链接程序可把它与其它可重定位文件及共享的目标文件一起处理来创建另一个目标文件;第二种是动态链接程序将它与另一个可执行文件及其它的共享目标文件结合到一起,创建一个进程映象。
    • 可执行文件:它包含了一个可以被操作系统创建一个进程来执行之的文件。
$ g++ -c ./main.s -o ./main.o # 生成二进制文件

无法直接打开

$ du -sh ./main.o # 查看文件大小
 	16K    ./main.o

4、链接

  • 链接就是把每个源代码独立编译后的结果,然后按照它们的要求将它们组装起来,链接主要解决的是源代码之间的相互依赖问题,链接的过程包括地址和空间的分配,符号决议,和重定位等这些步骤
$ g++ ./main.o -o main.out # 链接处理

生成main.out可执行文件(windows下应生成.exe文件)

$ main.out # 执行文件
	Hello World

抄袭的文章

c/c++编译过程

How C++ Works: Understanding Compilation