C++ 环境准备

sudo apt-get install g++ 安装编译器。
sudo apt-get install gdb 安装调试器。
在 vscode 中安装拓展

编译指令

简单:”g++ 选项 源文件名”,例如 g++ -o test main.cpp
高级:”g++ 选项 源文件名 输出选项 链接库”,例如 g++ -std=c++17 -Wall -O2 -I./include main.cpp -o my_app -L./lib -lpthread

  1. 编译选项
    -std=c++17 指定 C++ 标准。
    -I./include 指定头文件搜索路径。
    -g 调试, Wall 警告。
    -On 编译、链接时优化,提高可执行程序运行速度,减慢编译速度,默认 -O0, 推荐 -O2
    -c 只编译不链接,常用于把源文件编译成静态库或动态库。

  2. 输出选项
    -o 文件名 指定输出文件名。

  3. 链接库
    -L./libs 指定库文件搜索路径。
    -l库文件名 链接库,若库文件名为 libpthread.so 则命令为 -lpthread

静态库和动态库

若动态库和静态库同时存在,编译器将优先使用动态库。

概念与特点

静态库:程序在编译时把库文件的二进制代码链接到目标程序中,这种方式称为静态链接。
如果多个程序中用到了同一静态库中的函数或类,就会存在多份拷贝

  • 静态库的链接在编译时期完成,执行时代码加载速度快。
  • 目标程序的可执行文件较大,浪费空间。
  • 程序的更新和发布不方便,一个静态库更新后,所有使用它的程序都需要重新编译。

动态库:程序在运行时把库文件的二进制代码载入。
如果多个进程中用到了同一动态库中的函数或类,内存中只会存在一份,避免了空间浪费问题

  • 可实现进程间的代码共享,因此动态库也称为共享库。
  • 程序升级较简单,无需重新编译程序,只需更新动态库即可。
  • 需要提前设置 LD_LIBRARY_PATH 环境变量。

制作

  1. 制作静态库
    1.”g++ -c 源代码文件清单”,如 g++ -c source1.cpp source2.cpp source3.cpp
    2.”ar rcs lib库名.a 目标文件清单”,如 ar rcs libmylib.a source1.o source2.o source3.o

  2. 制作动态库
    “g++ -fPIC -shared 源代码文件清单 -o lib库名.so”,如 g++ -fPIC -shared math.cpp -o libmymath.so

Makefile 与 CMake

Makefile

  1. 在目录下创建文件 “Makefile” ,编写命令内容。开头需要使用 Tab 缩进,而非空格
  2. 运行命令 make 即可编译链接出可执行程序,使用 “./程序名” 运行。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    # # v1
    # test: main.cpp printhello.cpp factorial.cpp
    # g++ -o test main.cpp printhello.cpp factorial.cpp

    # # v2
    # CXX = g++
    # TARGET = test
    # OBJ = main.o printhello.o factorial.o
    # # make 时执行 g++, 先找 TARGET , TARGET 不存在找 OBJ, OBJ 不存在,编译三个 .cpp 文件生成 .o 文件
    # # 然后再链接 OBJ 文件,生成可执行文件 hello
    # $(TARGET): $(OBJ)
    # $(CXX) -o $(TARGET) $(OBJ)
    # # 编译 OBJ
    # main.o: main.cpp
    # $(CXX) -c main.cpp
    # printhello.o: printhello.cpp
    # $(CXX) -c printhello.cpp
    # factorial.o: factorial.cpp
    # $(CXX) -c factorial.cpp

    # v3
    CXX = g++
    TARGET = hello
    OBJ = main.o printhello.o factorial.o
    # 编译选项,显示所有的warning
    CXXFLAGS = -c -Wall
    # $@表示的就是冒号前面的TARGET,$^表示的是冒号后OBJ的全部.o依赖文件
    $(TARGET): $(OBJ)
    $(CXX) -o $@ $^
    # $<表示指向%.cpp依赖的第一个,但是这里依赖只有一个
    # $@表示指向%.o
    %.o: %.cpp
    $(CXX) $(CXXFLAGS) $< -o $@
    # 为了防止文件夹中存在一个文件叫clean
    .PHONY: clean
    # -f表示强制删除,此处表示删除所有的.o文件和TARGET文件
    clean:
    rm -f *.o $(TARGET)

CMake

  1. 在项目根目录下创建 .txt文件 CMakeLists.txt ,编写内容。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    cmake_minimum_required(VERSION 3.10)

    project(test)

    set(CMAKE_CXX_STANDARD 20) # 指定 C++ 标准

    add_executable(test main.cpp factorial.cpp printhello.cpp)

    ## 自动查找当前目录下所有的源文件,并将列表赋值给变量 SRC_LIST
    #aux_source_directory(. SRC_LIST)

    ## 使用变量 SRC_LIST 编译程序,不用手写 main.cpp factorial.cpp ...
    #add_executable(test ${SRC_LIST})
  2. 创建 “build” 文件夹 mkdir build ,进入该目录 cd build
  3. 运行命令 cmake .. ,执行根目录的内容,在当前目录生成 “Makefile”。
  4. 运行命令 make 即可编译链接出可执行程序,使用 “./程序名” 运行。

GDB 调试

待写

Linux 的系统错误

待写

Linux 的信号

其他

Linux 的时间操作

Linux 的目录操作

stat 结构体

struct stat 结构体用于存放目录或文件的详细信息,成员变量比较多,重点关注 st_mode, st_sizest_mtime 成员。
注意:
st_mtime 是一个整数表示的时间,需要程序员自己写代码转换格式。
st_mode 成员的取值很多,用以下两个宏来判断:
S_ISREG(st_mode) 是否为普通文件,如果是,返回真。
S_ISDIR(st_mode) 是否为目录,如果是,返回真。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct stat 
{
dev_t st_dev; // 文件的设备编号。
ino_t st_ino; // 文件的i-node。
mode_t st_mode; // 文件的类型和存取的权限。
nlink_t st_nlink; // 连到该文件的硬连接数目,刚建立的文件值为1。
uid_t st_uid; // 文件所有者的用户识别码。
gid_t st_gid; // 文件所有者的组识别码。
dev_t st_rdev; // 若此文件为设备文件,则为其设备编号。
off_t st_size; // 文件的大小,以字节计算。
size_t st_blksize; // I/O 文件系统的I/O 缓冲区大小。
size_t st_blocks; // 占用文件区块的个数。
time_t st_atime; // 文件最近一次被存取或被执行的时间,
// 在用mknod、 utime、read、write 与tructate 时改变。
time_t st_mtime; // 文件最后一次被修改的时间,
// 在用mknod、 utime 和write 时才会改变。
time_t st_ctime; // 最近一次被更改的时间,在文件所有者、组、 权限被更改时更新。
};