C++进阶篇:001

news/2025/10/22 14:18:17/文章来源:https://www.cnblogs.com/Khalil1314/p/19157865
C++进阶篇:001

C++进阶篇:001.linux入门

一、vim编辑器的使用

1.如何打开vim编辑器

	1. 先touch一个文件,然后使用指令:vi/vim + filename即可,这种方式打开文件,无论是否编辑文件,都会在文件系统中产生一个普通文件2. 直接使用vi/vim + 不存在的文件名,如果对文本内容进行更改,则保存退出后,会在文件系统上产生一个普通文件,如果没有更改数据,保存后退出,则不会创建该文件

2.命令行模式

	1.使用vi + 文件名,刚进入编辑器的模式就是命令行模式2.命令行模式的使用,主要完成对文本内容整体的复制、粘贴、剪切、删除、光标移动等操作3.命令行模式的主要操作:yy:复制当前行的文本内容nyy:复制光标所在行及以后的n行文本内容p:将剪切板中的内容进行粘贴dd:删除光标所在的一行文本内容ndd:删除光标所在行及以后的n行文本内容u:撤销上一步操作ctrl + r:反撤销gg:将光标直接跳到首行位置nG:将光标跳到第n行0:表示光标移动到当前行行首位置$(ctrl + shift + 4):表示光标移动到当前行行尾位置

3.插入模式

	1.功能:用于文件内容的编辑2.如何进入插入模式:只能从命令行模式进入,不能从底层模式进入键盘上特殊的键能从命令行模式进入插入模式:Insert键:从光标所在的字符前进入插入模式i键:从光标所在的字符前进入插入模式I键:从光标所在行行首进入插入模式a键:从光标所在的字符后面进入插入模式A键:从光标所在行行尾进入插入模式o键:从光标所在行的下一行进入插入模式O键:从光标所在位置的上一行进入插入模式s键:删除光标所在的字符后,从光标位置进入插入模式S键:删除光标所在的一行文本后,从当前行进入插入模式

4.底行模式

	1.功能:完成对文本内容的保存、退出操作或者替换、查找工作2.如何进入底行模式:从命令行模式中键入shift + :(其实就是输入一个冒号)3.主要操作:w	保存文本内容:q	退出编辑器:q!	强制退出:wq	保存后退出:x	保存后退出:set number	显示行号:set nonumber 不显示行号:/string 查找字符串string,并将光标指向该字符串的首位置:%s/string1/string2/g 表示将所有的string1更换成string2:m,ns/string1/string2/g 表示[m, n]行闭区间内的所有string1更换成string2

二、可执行程序编译过程

1.如何将程序编译生成可执行程序

方法一

一步到位的编译
1.g++ ***.cpp	//此时会默认生成一个 a.out 的可执行程序
2.g++ ***.cpp -o 可执行程序名称	//此时会生成可执行程序

方法二(重要!)

分步编译:			ESc  -->  .iso
1.预处理(Pre_processing)功能:将源程序头文件展开、删除、注释、宏替换语法格式:g++ -E ***.cpp -o ***.i2.编译(Compiling)功能:将程序编译生成汇编语言语法格式:g++ -S ***.i -o ***.s3.汇编(Assembling)功能:将汇编语言编译生成二进制文件语法格式:g++ -c ***.s -o ***.o4.链接(Linking)功能:链接相关库文件,生成可执行程序语法格式:g++ ***.o -o 可执行程序

三、sys库的使用

1.什么是man手册

linux系统提供的有关函数或指令介绍的相关帮助手册,可以在该手册页中查看函数、指令的功能。一共有七章内容,主要使用前三章,第一章是shell指令相关说明,第二章是系统调用函数相关说明(重点),第三章是库函数(重要)

2.man手册的使用

进入手册:只需要键入man + 相关函数/指令即可

退出手册:键入q

3.查询指令

1

4.C语言函数库

如果想要查看C语言库函数相关功能,需要安装相关库

sudo yum install man-pages man-pages-devel

image-20251013220109555

5.常用的内核提供的函数库sys

  1. 文件的操作:open()、read()、write()、close()、lseek() 等等
  2. 进程控制函数:fork()、exit()、wait()、execl() 等等
  3. 信号操作:kill()、signal() 等等
  4. 网络通信:socket()、bind()、listen() 等等

6.使用GDB调试程序

  1. 在linux系统下的警告和错误,当程序出现bug时,linux终端会给大家两种不同的信息

    警告(warning):有时的警告是不影响可执行程序的产生

    image-20251013225133499

    错误(error):错误如果不改正,是不能生产可执行程序的

    image-20251013225048293

    总结:相比于gcc编译器,g++编译器要求更严格

    ​ 警告可以被忽略,继续产生可执行程序,但是错误必须更改后才能产生可执行程序

  2. 什么是gdb:https://www.sourceware.org/gdb/

    GDB,GNU项目调试器,允许您查看一个程序执行时"内部"发生了什么,或者一个程序崩溃时正在做什么

  3. gdb是干啥的

    gdb只要做四件事:

    启动程序,指定可能影响其行为的任何内容。
    使程序在指定条件下停止。
    检查程序停止时发生了什么。
    更改程序中的内容,这样您就可以尝试纠正一个错误的影响,并继续了解另一个错误。
    

    gdb可以调试指定的当前程序,向程序中传递参数

    gdb还可以调试出错的文件,查看错误原因

    gdb还可以调试正在运行的进程

  4. 如何使用gdb

    1)准备C++程序

    #include <iostream>
    #include <stdio.h>using namespace std;void print()
    {cout << "hello world" << endl;cout << "这是要我想说给大家听的!!!" << endl;}
    int main(int argc, const char* argv[])
    {int arr[5] = {1, 2, 3, 4, 5};int i = 0;for(i = 0; i < 5; i++){cout << arr[i] << " ";}cout << endl;print();return 0;
    }
    

    2)编译程序,编译选项中需要加上 -g

    g++ -g ***.cpp -o ***
    

    3)启动gdb调试

    gdb ./***
    

    image-20251013232008096

4)gdb常用指令

​ quit (q):表示退出gdb模式

​ run (r):表示执行可执行程序,如果没有设置断点,则将整个程序从头到尾执行一遍

​ list (l):展示可执行程序的相关行信息,默认展示10行

​ list m, n:表示展示从m行到n行的信息

​ list func:表示展示func函数旁边的相关程序

image-20251013233008799

![image-20251013233043217](C:\Users\Lenovo\Desktop\md\assets\image-20251013233043217.png)	

​ break (b):表示设置断点,当调试器将程序运行到断点所在位置后,会暂停于此

​ break 行号:表示在某行设置断点

​ break func:表示在指定的函数处设置断点

​ info break:查看所有断点的信息

​ delete breakpoint 断点编号:表示删除指定的断点

image-20251014214835368

​ next (n):表示执行下一条语句

​ continue(c):表示从断点处继续向后执行,直到遇到下一个断点或者程序结束

image-20251013234223923

​ step(s):能够跳入到指定函数中,查看相关函数内部代码

image-20251014220027841

​ print(p) 变量名/地址:表示打印指定变量或地址信息

image-20251014220952643

​ set variable 变量名=值:表示给某个变量设置相关的值

image-20251014221117516

gdb使用小技巧

​ shell:后面可以跟终端指令,表示执行终端相关操作

​ set logging on:设置开启日志功能,会在当前目录中生成一个gdb.txt文档文件记录接下来的调试内容

​ watchpoint:观察点,如果设置的观察点的值发生改变,则会将该值的旧值和新值全部展示出来

image-20251014223506162

gdb调试出错的文件

当一个可执行程序出现错误时,会产生一个core文件,用于查看相关错误信息

linux系统默认是不产生core文件,需要进行相关设置后才能产生

通过ulimit -a 查看所有linux的限制内容

image-20251014225141602

通过 ulimit -c unlimited来设置core文件的个数

image-20251014225733857

查看错误原因

image-20251014225803632

gdb调试其他正在运行的进程

./可执行程序 & :表示将可执行程序后台运行,不占用当前终端

image-20251014230622045

[zpp@localhost day2]$ g++ -g 05test.cpp                 //编译程序
[zpp@localhost day2]$ ./a.out &                       //后台运行程序
[1] 26837                                           //显示当前后台运行程序的作业号和
进程号
[zpp@localhost day2]$ gdb -p 26837                   //调试指定的运行的进程
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-120.el7 
4> 库的制作(静态库与动态库) 
1、为什么引入库
在上述案例中,主程序要是有的源程序代码,在add.cpp中,如果项目结束后,到了交付阶段,由
于主程序的生成需要其他程序联合编译,那么就要将源程序打包一起发给老板,这样该程序的开发者自
身的价值就不大了,该项目的知识产权就很容易被窃取。为了保护我们的知识产权,我们引入了库的概
念。
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Attaching to process 26837
Reading symbols from /home/zpp/day2/a.out...done.
Reading symbols from /lib64/libstdc++.so.6...(no debugging symbols 
found)...done.
Loaded symbols for /lib64/libstdc++.so.6
Reading symbols from /lib64/libm.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib64/libm.so.6
Reading symbols from /lib64/libgcc_s.so.1...(no debugging symbols found)...done.
Loaded symbols for /lib64/libgcc_s.so.1
Reading symbols from /lib64/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib64/libc.so.6
Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols 
found)...done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
main (argc=1, argv=0x7ffd31897908) at 05test.cpp:17
17 int main(int argc, const char *argv[])                 //进程运行在某处
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.x86_64 
libgcc-4.8.5-44.el7.x86_64 libstdc++-4.8.5-44.el7.x86_64
(gdb) n
22 test();
(gdb) n
23 test1();
(gdb) step
test1 () at 05test.cpp:12
12 int num = 520;
(gdb) n
13 num++;
(gdb) c
Continuing.

四、库的概念、动态库与静态库

1.为什么引入库

image-20251015152416467

在上述案例中,主程序要是有的源程序代码,在add.cpp中,如果项目结束后,到了交付阶段,由于主程序的生成需要其他程序联合编译,那么就要将源程序打包一起发给老板,这样该程序的开发者自身的价值就不大了,该项目的知识产权就很容易被窃取。为了保护我们的知识产权,我们引入了库的概念。

2.什么是库

库在linux中是一个二进制文件,它是由.cpp文件(不包含main函数)编译而来,其他程序如果想要使用该源文件中的函数时,只需要在编译生成可执行程序时,链接上该源文件生成的库文件即可。库中存储的是二进制文件,不容易被窃取知识产权,做到了保护作用。

库在linux系统中分为两类,分别是静态库和动态库

​ windows:

​ ***.lib(静态库)

​ ***.dll(动态库)

​ linux:

​ ***.a:静态库

​ ***.so:动态库

3.静态库及其制作

概念:将一个***.cpp的文件编译生成一个lib***.a的二进制文件,当你需要使用该源文件中的函数时,只需要链接该库即可,后期可以直接调用
静态体现在:在使用g++编译程序时,会将你的文件和库最终生成一个可执行程序(把静态库也放入到可执行程序中),每个可执行程序单独拥有一个静态库,体积较大,但是执行效率较高

3.1准备程序

add.h

#ifndef _ADD_H_
#define _ADD_H_int add(int m, int n);          //函数声明#endif

add.c

int add(int m, int n)
{return m+n;
}

main.cpp

#include<iostream>
#include<stdio.h>
#include "add.h"using namespace std;int main(int argc, const char *argv[])
{cout << add(3,8) << endl;       //调用外部文件中的相关函数return 0;
}

3.2编译生成静态库

g++ -c ***.c -o ***.o	//只编译不链接,生成二进制文件
ar -crs lib***.a ***.o	//编译生成静态库如果有多个.o文件共同编译生成静态库:ar -crs lib***.a ***.o xxx.o ...ar:用于生成静态库的指令
-c:用于生成静态库
-r:将文件插入或替换进静态库中同名文件
-s:重置静态库索引

3.3使用静态库

g++ main.cpp -L 库的路径 -l库名 -I 头文件的路径		//注意l和库名之间没有空格,而且库名不是lib***,而是***

image-20251015192325526

image-20251015193048574

4.动态库及其制作

概念:将一个***.cpp的文件编译生成一个lib***.so的二进制文件,当你需要使用该源文件中的函数时,只需要链接该库即可,后期可以直接调用
动态体现在:在使用g++编译程序时,会将你的文件和库中的相关函数的索引表一起生成一个可执行程序(把静态库也放入到可执行程序中),每个可执行程序只拥有函数的索引表,当程序执行到对应函数时,会根据索引表动态寻找相关库所在位置进行调用。体积较小,执行效率较低,但是可以多个程序共享同一个动态库,所以动态库也叫共享库

4.1准备程序

add.h

#ifndef _ADD_H_
#define _ADD_H_int add(int m, int n);          //函数声明#endif

add.c

int add(int m, int n)
{return m+n;
}

main.cpp

#include<iostream>
#include<stdio.h>
#include "add.h"using namespace std;int main(int argc, const char *argv[])
{cout << add(3,8) << endl;       //调用外部文件中的相关函数return 0;
}

4.2编译生成动态库

g++ -fPIC -c ***.cpp -o ***.o	//编译生成二进制文件
g++ -shared ***.o -o lib***.so	//依赖于二进制文件生成一个动态库上述两个指令可以合成
g++ -fPIC -shared ***.cpp -o lib***.so

4.3使用动态库

image-20251015194729773

4.4以上错误的解决方式

方法1:更改路径的宏

export LD_LIBRARY_PATH=库的路径		//不要乱加括号!!!

image-20251015195232936

方法2:将自己的动态库放入到系统的库函数目录中(/lib64 or /usr/lib)

image-20251015195907929

4.5动态库和静态库编译生成可执行程序的大小比较

image-20251015200138201

5.如何使用第三方库

  1. C/C++语言默认支持标准输入输出库的,但是其他的相关函数库需要第三方引入,并且,编译程序时,需要链接上对应的库
  2. 使用数学库:#include <math.h>

image-20251015215228149

  1. 线程支持类库:#include <pthread.h>

    如果不能支持线程进程库:sudo yum install manpages-posix manpages-posix-dev

image-20251015220437103

五、Makefile

1.什么是Makefile

用于工程项目管理的一个文本文件,文件名为Makefile
Makefile可以大写也可以小写,一般Makefile首字母使用大写
如果Makefile和makefile都存在,系统会默认使用小写的

image-20251015222052042

2.什么是make

make是一个执行Makefile的工具,是一个解释器,用来对Makefile中的命令进行解析并执行一个shell指令
make这个指令在 /usr/bin 中
如果没有安装make这个指令,安装指令如下:sudo yum install make

3.Makefile的用途

描述了整个工程的编译、链接规则
软件项目的自动化编译,相当于给软件编译写一份脚本文件

4.学习Makefile的必要性

Linux/Unix环境下开发的必备技能
系统架构师、项目经理的核心技能
研究开源项目、Linux内核源码的必需品
加深对底层软件构造系统及过程的理解

5.如何学习Makefile

  1. 理论基础

    软件的构造过程、程序的编译和链接:预处理->编译->汇编->链接面向依赖的思想:
    依赖一个.cpp文件的程序
    可执行程序  <--依赖于--  .o文件  <--依赖于--  .s文件  <--依赖于--  .i文件  <--依赖于--  .cpp文件依赖多个.cpp文件的程序
    可执行程序  <--依赖于--  .o文件  <--依赖于--  .s文件  <--依赖于--  .i文件  <--依赖于--  .cpp文件|  --  .o文件  <--依赖于--  .s文件  <--依赖于--  .i文件  <--依赖于--  .cpp文件|  --  .o文件  <--依赖于--  .s文件  <--依赖于--  .i文件  <--依赖于--  .cpp文件|  --  .o文件  <--依赖于--  .s文件  <--依赖于--  .i文件  <--依赖于--  .cpp文件......
    
  2. 项目编程基础

    C++程序语言基础
    C语言基础
    多文件原码管理、头文件包含、函数声明与定义
    

6.Makefile的工作过程

Makefile本身是面向依赖进行编写的
源文件  --->  编译  --->  目标文件  --->  链接  --->  可执行文件
hello.cpp  --->  hello.o  --->  hello
本质上一步就可以生成可执行程序,但是,由于在生成可执行程序时,可能会有多个文件进行参与,后期其他文件可能要进行更改,更改后,会影响到可执行程序的执行,其他没有更改的文件也要参与编译,浪费时间

7.第一个Makefile

  1. 编写一个hello.cpp文件

    #include<iostream>
    #include<stdio.h>
    using namespace std;
    int main(int argc, const char *argv[])
    {cout << "hello world" << endl;return 0;
    }
    

    2.通过终端编译程序

    image-20251015224528339

    3.使用Makefile管理功能

    编写Makefile文件

    # Makefile中的注释是以#开头
    # 语法格式:
    # 目标:依赖
    # 通过依赖生成目标的指令
    # 注意:指令前面必须使用同一个tab键隔开,不能使用多个空格顶过来hello:hello.og++ hello.o -o hellohello.o:hello.sg++ -c hello.s -o hello.ohello.s:hello.ig++ -S hello.i -o hello.shello.i:hello.cppg++ -E hello.cpp -o hello.i

    简化的Makefile文件

    # Makefile中的注释是以#开头
    # 语法格式:
    # 目标:依赖
    # 通过依赖生成目标的指令
    # 注意:指令前面必须使用同一个tab键隔开,不能使用多个空格顶过来
    hello:hello.og++ hello.o -o hello
    hello.o:hello.cppg++ -c hello.cpp -o hello.o

    4.执行Makefile文件

    make  --->  默认找到Makefile中的第一个目标开始进行执行
    make 目标  --->  找到对应的目标进行执行
    

    image-20251015231647760

8.Makefile的语法规则

  1. 规则

    构成Makefile的基本单元,构成依赖关系的核心部件

    其他内容可以看作为规则的服务

  2. 变量

    类似于C++中的宏,使用变量:$(变量名) 或者 ${变量名}

    作用:使得Makefile更加灵活

  3. 条件执行

    根据某一变量的值来控制make执行或者忽略Makefile的某一部分

  4. 函数

    文本处理函数:字符串的替换、查找、过滤等等

    文件名的处理:读取文件/目录名、前后缀等等

  5. 注释

    Makefile中的注释,是以#号开头

9.规则

1、规则的构成:目标、目标依赖、命令

2、语法格式

目标:目标依赖命令注意事项:命令必须使用tab键开头,一般是shell指令一个规则中,可以无目标依赖,仅仅是实现某种操作一个规则中可以没有命令,仅仅描述依赖关系

image-20251016134540035

3、目标详解

1)默认目标

一个Makefile里面可以有多个目标,一般选择第一个当做默认目标
也就是make默认执行的目标

2)多目标

一个规则中可以有多个目标,多个目标具有相同的生成命令和依赖文件

clean distclean:rm hello.[^cpp] hello

image-20251016140052755

3)多规则目标

多个规则可以是同一目标

all:test1
all:test2
test1:echo "hello"
test2:echo "world"

image-20251016141721055

4)伪目标

并不是一个真正的文件名,可以看做是一个标签
无依赖,相比一般文件,不会重新生成、执行
伪目标:可以无条件执行,相当于对应的指令eg:.PHONY:clean	#设置伪目标clean:rm hello.[^cpp] hello

image-20251016142911979

4、目标依赖

1)文件时间戳

根据时间戳来判断目标依赖是否要进行更新
所有文件都更改过,则对所有文件进行编译,生成可执行程序
在上次make之后修改过的cpp文件,会被重新编译
在上次make之后修改过的头文件,依赖该头文件的目标依赖也会重新编译

2)模式匹配

%		---->通配符匹配
$@		---->目标
$^		---->依赖
$<		---->第一个依赖
*		---->普通通配符注意:%是Makefile中的规则通配符,*是普通通配符
头文件
#ifndef _OPERATOR_H
#define _OPERATOE_H
int add(int m, int n);
#endif
源文件
int add(int m, int n)
{return m+n;
}
主程序:
#include<iostream>
#include"operator.h"
using namespace std;
int main(int argc, const char *argv[])
{cout << add(3,5) << endl;return 0;
}
#第一个依赖关系
all:operator
operator:main.o operator.o
# g++ main.o operator.o -o operatorg++ $^ -o $@
#main.o:main.cpp
# g++ -c $< -o $@
#operator.o:operator.cpp
# g++ -c $^ -o $@
#将上述两个规则统一成一个规则5、命令
 
10> 变量 
1、变量基础
2、变量的分类
3、变量的外部传递
可以通过命令行给变量进行赋值操作make ARCH=g++
#此时的%表示所有的Makefile内容,不能换成*
%.o:%.cppg++ -c $< -o $@
clean:rm -f *.o operator         #此处的*是普通通配符

5、命令

1)命令的组成由shell命令组成,以tab键开头2)命令的执行每条命令执行完,make会检测这个命令的返回码如果返回成功,则继续执行后面的命令如果返回失败,则make会终止当前执行的规则并退出3)并发执行命令make -j4	----->表示开辟4个线程执行time make	----->执行make时,显示当前时间

10.变量

1、变量基础

1)变量定义:变量名 = 变量值
2)变量的赋值追加赋值:+=		--->在原有的基础上追加相关内容条件赋值:?=		--->如果之前没有值,则为变量赋值,如果之前有值,则不进行赋值
3)变量的使用:	$(变量名)或者${变量名}

2、变量的分类

1)理解展开变量使用:=操作符进行赋值在解析阶段直接复制常量字符串
2)延迟展开变量使用=操作进行赋值将最后一次赋值的结果给变量名使用
3)注意事项一般在目标、目标依赖中使用立即展开赋值在命令中一般使用延迟展开赋值

3、变量的外部传递

可以通过命令行给变量进行赋值操作

​ make ARCH=g++

var1 = main.o          #定义一个变量并赋值
var1 += operator.o #给变量追加值
CC:=g++
#第一个依赖关系
all:operator
operator:$(var1)
# g++ main.o operator.o -o operator$(CC) $^ -o $@
#main.o:main.cpp
# g++ -c $< -o $@
#operator.o:operator.cpp
# g++ -c $^ -o $@
#将上述两个规则统一成一个规则
#此时的%表示所有的Makefile内容,不能换成*
%.o:%.cpp$(CC) -c $< -o $@
clean:rm -f *.o operator          #此处的*是普通通配符

11.条件执行

1、关键字

ifeq、else、endif
ifneq、else、endif

2、使用

ifeq (要判断的量,判断的值)Makefile语句
elseMakefile语句
endif注意:条件语句从ifeq开始执行,括号与关键字之间使用空格隔开括号里面挨着括号处,不允许加空格

image-20251018133115661

12.总结

1、执行过程

进入编译目录、执行make命令
依赖关系解析阶段
命令执行阶段

2、依赖解析阶段

解析Makefile,建立依赖关系树
控制解析过程,引入Makefile,变量展开、条件执行

3、命令执行阶段

把解析生成的依赖关系树加载到内存
按依赖关系,按顺序生成这些文件
再次编译make会检测文件的时间戳,判断是否过期如果无过期,在不在编译如果文件有更新,则依赖该文件的所有依赖关系上的目标都会重新编译

4、make执行结果

make的退出码0:表示成功执行1:表示允许错误,退出

13.参考源码

1、头文件

#ifndef _OPERATOR_H
#define _OPERATOE_Hint add(int m, int n);#endif

2、源文件

int add(int m, int n)
{return m+n;
}

3、主程序

#include<iostream>
#include"operator.h"
using namespace std;
int main(int argc, const char *argv[])
{cout << add(3,5) << endl;return 0;
}

4、Makefile

var1 = main.o         #定义一个变量并赋值
var1 += operator.o #给变量追加值
#条件选择,如果变量COMPILE的值是g++那么CC的值就是g++,否则是gcc
ifeq ($(COMPILE), g++)CC:=g++
elseCC:=gcc
endif
#第一个依赖关系
all:operator
operator:$(var1)
# g++ main.o operator.o -o operator$(CC) $^ -o $@
#main.o:main.cpp
# g++ -c $< -o $@
#operator.o:operator.cpp
# g++ -c $^ -o $@
#将上述两个规则统一成一个规则
#此时的%表示所有的Makefile内容,不能换成*
%.o:%.cpp$(CC) -c $< -o $@
clean:rm -f *.o operator         #此处的*是普通通配符

六、vsc中使用cmake

1.前言

1> CMake是一个跨平台的安装编译工具,可以使用简单的语句来描述所有平台的安装(编译过程)

2> CMake可以说是已经成为大部分的C++开发项目的标配

3> 可以使用几行或者几十行的代码来完成非常冗长的Makefile代码

2.为什么要使用CMake

1> 在不使用CMake时,编译工程如下

image-20251018235323785

2> 在上面的机制中,工程文件中添加一个源程序,bar.cpp

image-20251018235610952

3> 使用CMake来管理工程的状态

image-20251019000241765

4> 使用CMkake管理工程中添加一个新文件 bar.cpp

image-20251019000609455

3.语法特性介绍

  1. 基本语法:指令(参数1 参数2 ...)

​ 参数使用括号括起来

​ 参数之间使用空格或分号隔开

  1. 注意:指令是大小写无关的,但是参数和变量是大小写相关的
set(HELLO hello.cpp)	# 定义一个变量名叫HELLO 变量的值为hello.cpp
add_executable(hello main.cpp hello.cpp)	# 通过main.cpp 和 hello.cpp 编译生成hello可执行程序
ADD_EXECUTABLE(hello main.cpp ${HELLO})		#作用同上
  1. 变量使用${}进行取值,但是在if控制语句中,是直接使用变量名的

​ if(HELLO) 是正确的

​ if(${HELLO}) 是不正确的

4.重要的指令

  1. cmake_minimum_required:指定cmake的最小版本支持,一般作为第一条cmake指令

    # CMake设置最小支持版本为 2.8
    cmake_minimum_required(VERSION 2.8)
    
  2. project:定义工程的名称,并可以指定工程支持的语言

    # 指定工程的名称为HELLOWORLD
    project(HELLOWORLD CXX)		# 表示工程名为HELLOWORLD	使用的语言为C++
    
  3. set:显式定义变量

    # 定义变量 SRC 其值为 sayhello.cpp hello.cpp
    set (SRC sayhello.cpp hello.cpp)
    
  4. add_executable:通过依赖生成可执行程序

    # 编译main.cpp 生成main的可执行程序
    add_executable(main main.cpp)
    
  5. include_directories:向工程添加多个特定的头文件搜索路径,类似于g++编译指令中的 -I

    # 将/usr/lib/mylibfolder 和 ./include添加到工程路径中
    include_directories(/usr/lib/mylibfolder ./include)
    
  6. link_directories:向工程中添加多个特定的库文件搜索路径,类似于g++编译指令中的 -L

    # 将/usr/lib/mylibfolder 和 ./lib添加到库文件搜索路径中
    link_directories(/usr/lib/mylibfolder ./lib)
    
  7. add_library:生成库文件(包括动态库和静态库)

    # 通过SRC变量中的文件,生成库hello
    add_library(hello SHARED ${SRC})	#该语句生成的是动态库
    add_library(hello STATIC ${SRC})	#该语句生成的是静态库
    
  8. add_compile_options:添加编译参数

    # 添加编译参数	-Wall  -std=c++11
    add_compile_options(-Wall -std=c++11)
    
  9. target_link_libraries:为target添加需要链接的共享库

    # 将hello 动态库文件链接到可执行程序main中
    target_link_libraries(main hello)
    

5.CMake常用变量

  1. CMAKE_C_FLAGS:gcc编译选项的值

  2. CMAKE_CXX_FLAGS:g++编译选项的值

    # 在CMAKE_CXX_FLAGS编译选项后追加 -std=c++11
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
    
  3. CMAKE_BUILD_TYPE:(Debug、Release)

    # 设定编译类型为Debug,调试时需要选择该模式
    set(CMAKE_BUILD_TYPE Debug)# 设定编译类型为Release,发布时需要选择该模式
    set(CMAKE_BUILD_TYPE Release)
    

6.CMake编译工程

CMake目录结构:项目主目录中会放一个CMakeLists.txt的文本文档,后期使用cmake指令时,依赖的就是该文档

  1. 包含源文件的子文件夹中包含CMakeLists.txt时,主目录的CMakeList.txt要通过add_subdirectory添加子目录
  2. 包含源文件的子文件夹中不包含CMakeLists.txt文件时,子目录编译规则,体现在主目录中的CMakeLists.txt中

6.1 两种构建方式

  1. 内部构建:不推荐使用

    内部构建会在主目录下,产生一大堆中间文件,这些中间文件并不是我们最终所需要的,和工程源文件放在一起时,会显得比较杂乱无章

    ## 内部构建# 在当前目录下,编译主目录中的CMakeLists.txt文件生成Makefile文件
    cmake .		# .表示当前路径
    # 执行make命令,生成目标文件
    make
    
  2. 外部构建:推荐使用

    将编译输出的文件,与源文件放在不同的目录下,进行编译,此时,编译生成的中间文件不会跟工程源文件混淆

    ## 外部构建# 1、在当前目录下,创建一个build文件,用于存储生成中间文件
    mkdir build# 2、进入build文件夹
    cd build# 3、编译上一级目录中的CMakeLists.txt,生成Makefile文件以及其他文件
    camke ..	# ..表示上一级目录# 4、执行make命令,生成可执行程序
    make
    

7.CMake代码实战

7.1 同一目录下的文件进行编译

  1. 源文件

    #include <myhead.h>
    int main(int argc, const char *argv[]) 
    {   std::cout << "Hello, World!" << std::endl;      //输出一个hello world语句   return 0;
    }
    

    image-20251019103424456

  2. CMakeLists.txt文件

    # 设置最小版本支持
    cmake_minimum_required(VERSION 2.8)         
    # 项目名称
    project(HELLO)
    # 生成可执行程序,依赖于hello.cpp生成hello可执行程序
    add_executable(hello hello.cpp)
    
  3. 内部构建

    image-20251019103659499

image-20251019103745929

  1. 外部构建

image-20251019104655860

image-20251019104703634

7.2 分文件编译

1、头文件

#ifndef SWAP_H
#define SWAP_H
#include <iostream>
using namespace std;//声明一个交换类
class My_swap
{
private:int a;int b;      //两个成员变量
public://定义构造函数My_swap(int a, int b){this->a = a;this->b = b;}//声明交换函数void run();//声明打印函数void printInfo();};#endif

2、源文件

#include"swap.h"
//对交换函数的定义
void My_swap::run()
{   int temp = a;   a = b;    b = temp;
}
//对打印函数的定义
void My_swap::printInfo()
{   cout << "a = " << a<< endl;   cout << "b = " << b<< endl;
}

3、测试文件

#include "swap.h"
int main(int argc, const char *argv[]) 
{   //声明一个交换类对象,调用有参构造完成   My_swap my_swap(520, 1314);      //输出交换前的结果   my_swap.printInfo();      //520 1314   cout << "**************************" << endl;   //调用交换函数   my_swap.run();   //输出交换后的结果   my_swap.printInfo();      return 0;
}

4、分文件编译使用g++编译器生成可执行程序

image-20251019111101076

5、创建工程管理文件 CMakeLists.txt

# 指定最小编译版本
cmake_minimum_required(VERSION 2.8)
# 执行工程名称
project(SWAP)
# 指定头文件路径 就是 g++ 编译器的 -I 选项
include_directories(include)
# 生成可执行程序
add_executable(swap_cmake main.cpp src/swap.cpp)

image-20251019114733924

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/943330.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

卷积神经网络的读后感

深度探索图像的语言:卷积神经网络读后感 读完关于卷积神经网络的介绍,我仿佛打开了一扇通往图像世界的新视角。在此之前,我一直认为图像的本质只是像素点组成的二维矩阵,而CNN则像一位经验丰富的翻译官,教会我如何…

Calibre 8.11技术拆解:AI集成与二次开发的实战指南 - 教程

Calibre 8.11技术拆解:AI集成与二次开发的实战指南 - 教程2025-10-22 14:14 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !importan…

5G企业应用的七大场景与商业机遇

本文详细介绍了5G在企业领域的七大关键应用场景,包括固定无线接入、医疗健康、传感器系统、网络边缘计算、远程设备控制、汽车行业和智慧城市,分析了5G技术如何推动企业数字化转型和业务创新。尽管5G早期面临价格溢价…

2025 水泥墩源头厂家最新推荐排行榜:光伏 / 围挡 / 交通 / 防撞水泥墩多品类优选,实力品牌权威榜单

引言 水泥墩作为市政基建、光伏电站、交通防护等领域的核心基础建材,其质量直接关系到工程安全与使用寿命。2025 年国内水泥制品行业市场规模预计达 14850 亿元,华东地区占比近 30%,交通、光伏等领域需求持续攀升,…

类的多态(Num020) - 实践

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

2025 年国内活塞杆厂家最新推荐排行榜:聚焦精密 / 不锈钢 / 油缸 / 气缸 / 45# 镀铬类产品,助力企业精准挑选可靠合作方

引言 当前工业自动化进程持续加速,活塞杆作为液压油缸、气缸等关键部件的核心组件,其质量直接关乎设备运行精度与使用寿命。但当下市场中,活塞杆制造商良莠不齐,部分企业产品存在工艺粗糙、精度不足、耐腐蚀性能差…

20232305 2025-2026-1 《网络与系统攻防技术》实验二实验报告

1.实验内容 (1)学习使用netcat监听端口,反弹链接到主机并获得shell; (2)使用netcat在liunx主机上增加一个定时任务,并学习使用socat; (3)使用MSF meterpreter生成可执行文件(后门),利用ncat或socat传送到…

就在Visual Studio Code中配置好C/C++

就在Visual Studio Code中配置好C/C++这篇随笔主要是闲暇时间写的,写这篇随笔的原因有以下两点: 1.唯一的一个粉丝说我好久没更新了。 2.我的直系学弟他说他用Visual Studio Code一直搞不好C,终端也实现不了。 好的…

高效数据结构 - 循环队列

循环队列在游戏开发中通常叫做CircularBuffer、RingBuffer,常用来做数据缓存,生产者/消费者模型等。 在UE中有内置这样的数据结构,而Unity的.Net库中恰恰没有。为什么说这样的结构高效,以双下标循环队列为例。配个…

数据类型,二元运算符,自动类型提升规则,关系运算,取余模运算

数据类型,二元运算符,自动类型提升规则,关系运算,取余模运算数据类型,二元运算符,自动类型提升规则,关系运算,取余模运算 package com.kun.operator;public class Demo1 {public static void main(String[] ar…

股票技术面分析平台QuantMatrix深度解析 - 实践

股票技术面分析平台QuantMatrix深度解析 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", &…

【C++实战(64)】C++ 邂逅SQLite3:数据库编程实战之旅 - 教程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

迷宫问题

#include <iostream> #include <stack> #include <vector> #include <climits> using namespace std;// 迷宫大小 const int ROW = 5; const int COL = 5;// 迷宫(0:可走,1:墙,起点(0,0)…

WPF使用MediaCapture开发相机应用(四、相机录视频)

在WPF中使用MediaCapture录视频还是挺简单的,教程是WinUI3的,WPF也可以直接用。 主要代码就几句,相对简单: var videos = await StorageLibrary.GetLibraryAsync(KnownLibraryId.Videos); StorageFile file = awai…

Gitee本土化战略深度解析:中国开发者生态的合规与效率革命

Gitee本土化战略深度解析:中国开发者生态的合规与效率革命 在数字化转型加速的背景下,代码托管平台已成为企业研发基础设施的核心组件。作为国内领先的代码托管服务商,Gitee通过深度本土化战略构建了独特的竞争优势…

2025年10月上海装修公司口碑榜:十强对比评测

站在2025年10月的节点,准备装修的你大概率正被三件事困扰:预算怕超、工期怕拖、质量怕翻车。上海存量房超过780万套,二次翻新需求占年度装修总量62%,老房结构复杂、物业审批流程长、材料涨价频繁,让“选一家靠谱装…

2025年10月中国婚姻家事与财富管理律师评价榜:五强评测

当婚姻、继承、股权、跨境资产交织在一起,普通人最先感受到的是信息碎片化:谁懂信托架构?谁能追踪隐匿账户?怎样在离婚谈判里既保住公司控制权又不伤孩子?2025年,高净值家庭数量已突破220万户,年均增长8%,而家…

LGP8969 幻梦 Dream with Dynamic

LGP8969 幻梦 Dream with Dynamic \(\texttt{Luogu Link}\) 前言 唉,强校。 抛开别的不谈,这题意外地好懂……吗? 本学习笔记解析部分抄袭此文,代码抄袭此文。 题意简述 有一个长度为 \(n\) 的序列 \(A\),有初值。…

2025年10月中国婚姻家事与财富管理律师推荐榜:五强对比评测

站在2025年深秋,高净值家庭与新兴中产同时面临一个共性焦虑:婚姻结构变化带来的财产不确定性。北京、上海、深圳三地法院2024年婚姻家事案件标的额均值已升至320万元,隐匿财产线索发现率却不足三成。与此同时,金税…

2025年10月工业洗地机厂家推荐榜:十强对比评测与选型指南

一、引言 工业洗地机已成为制造、物流、物业、交通枢纽等场景提升清洁效率、降低人工成本的刚需装备。对于计划2025年第四季度完成设备更新或首次采购的决策者而言,如何在同质化宣传中快速锁定技术可靠、服务及时、全…