C++编译和链接

文章目录

编译预处理

C++程序编译的过程:预处理-》编译(优化、汇编)-》链接

预处理指令主要有三种:

  • 包含头文件:#include
  • 宏定义:#define (定义宏)、#undef (删除宏)
  • 条件编译:#ifdef #ifndef

预处理做的事情

  • 处理#include 头文件包含指令
  • 处理#ifdef #else #endif、#ifndef #else #endif 条件编译指令
  • 处理#define 宏定义
  • 为代码添加行号、文件名和函数名
  • 删除注释
  • 保留部分#pragma编译器指令(编译的时候会用到)

包含头文件

#include包含头文件有两种方式:

  • #include<文件名>:直接从编译器自带的函数库目录中寻找文件
  • #include"文件名":先从自定义的目录中寻找文件,如果找不到,再从编译器自带的函数库目录
    中寻找
    include可以包含许多类型文件,本质就是将包含的文件复制到主文件中

宏定义

  • 无参数的宏:#define 宏名 宏内容
  • 有参数的宏:#define MAX(x,y) ((x)>(y)?(x):(y))

编译的时候,编译器把程序中的宏名用宏内容替换,称为宏展开

宏可以只有宏名,没有宏内容

C++常用宏:

  • 当前源代码文件名:__FILE__
  • 当前源代码函数名:__FUNCTION__
  • 当前源代码行号:__LINE__
  • 编译的日期:__DATE__
  • 编译的时间:__TIME__
  • 编译的时间戳:__TIMESTAMP__
  • 区分gcc和g++:__cplusplus

条件编译

最常用的两种:#iddef #ifndef

如果宏名存在,使用程序段一,不存在使用程序段二

cpp 复制代码
#ifdef 宏名
程序段一
#else
程序段二
#endif

如果宏名不存在,使用程序段一,不存在使用程序段二

等价于:

如果宏名存在,使用程序段二,不存在使用程序段一

cpp 复制代码
#ifdnef 宏名
程序段一
#else
程序段二
#endif

解决头文件重复包含问题

方法一、#ifndef

cpp 复制代码
#ifndef __DD
#define __DD



#endif

方法二、#pragma once

cpp 复制代码
#pragma once
xxx

#ifndef

  • 受C++语言标准支持,不受编译器的限制
  • 可以针对文件中的部分代码

#pragma once

  • 有的编译器不支持
  • 只能针对整个文件

编译和链接

源代码的组织

头文件.h#include 头文件、函数的声明、结构体的声明、类的声明、模板的声明、内联函数、#define 和 const 定义的常量等

源文件.cpp:函数的定义、类的定义、模板具体化的定义

主程序 main :主程序负责实现框架和核心流程,把需要用到的头文件用#include包含进来

编译

将预处理生成的文件,经过词法分析、语法分析、语义分析以及优化和汇编后,编译成若干个目标文

件(二进制文件)。

链接

将编译好的目标文件以及他们所需要的库文件链接在一起,形成一个整体

更多细节

  1. 分开编译好处:每次只编译修改过的源文件,然后再链接,效率更高
  2. 编译单个*.cpp文件的时候,必须要让编译器知道名称的存在,否则会出现找不到标识符的错误(直接或者间接包含头文件都可以)
  3. 编译单个*.cpp文件的时候,编译器只需知道名称的存在,不会其定义一起编译
  4. 如果函数或类定义不存在,编译不会报错,但是链接会出现无法解析的外部命令
  5. 链接的时候,变量、函数和类的定义只能有一个,否则会出现重定义的错误。(如果把变量、函数和类的定义放在*.h文件中,*.h 会被多次包含,链接前可能存在多个副本;如果放在*.cpp文件中,*.cpp文件不会被包含,只会被编译一次,链接前只存在一个版本)
  6. 把变量、函数和类的定义放在*.h中是不规范的做法,如果*.h被多个*.cpp包含,会出现重定义
  7. #include包含*.cpp也是不规范的做法,原理同上
  8. 尽可能不使用全局变量,如果一定要用,要在*.h文件中声明(extern关键字),在*.cpp文件中定义
  9. 全局的const 常量在头文件中定义(const 常量仅在单个文件内有效)。
  10. *.h文件重复包含的处理方法只对单个的*.cpp文件有效,不是整个项目。
  11. 函数模板和类模板的声明和定义可以分开书写,但它们的定义并不是真实的定义,只能放在*.h文件中;函数模板和类模板的具体化版本的代码是真实的定义,所以放在*.cpp文件中
相关推荐
FQNmxDG4S2 小时前
Java多线程编程:Thread与Runnable的并发控制
java·开发语言
前端老石人3 小时前
HTML 字符引用完全指南
开发语言·前端·html
matlab_xiaowang3 小时前
Redux 入门:JavaScript 可预测状态管理库
开发语言·javascript·其他·ecmascript
虹科网络安全3 小时前
艾体宝干货|数据复制详解:类型、原理与适用场景
java·开发语言·数据库
axng pmje4 小时前
Java语法进阶
java·开发语言·jvm
汉克老师4 小时前
GESP2025年3月认证C++五级( 第三部分编程题(1、平均分配))
c++·算法·贪心算法·排序·gesp5级·gesp五级
老前端的功夫4 小时前
【Java从入门到入土】28:Stream API:告别for循环的新时代
java·开发语言·python
qq_435287924 小时前
第9章 夸父逐日与后羿射日:死循环与进程终止?十个太阳同时值班的并行冲突
java·开发语言·git·死循环·进程终止·并行冲突·夸父逐日
止语Lab4 小时前
从手动到框架:Go DI 演进的三个拐点
开发语言·后端·golang
yaoxin5211234 小时前
397. Java 文件操作基础 - 创建常规文件与临时文件
java·开发语言·python