> For the complete documentation index, see [llms.txt](https://cifar.gitbook.io/note/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://cifar.gitbook.io/note/kai-fa/c++-zhi-shi.md).

# C++ 知识

高强度写了两天 Rust 和 Go 之后，今天写了会儿 Python，感觉大脑得到了解放，去 tm 的类型体操，我大 Python 想怎么写就怎么写，这才是大道至简  （可以写python通过chatgpt转其他语言）

## 编译链接

centos ： [gcc升级版本](https://blog.csdn.net/baidu_39332177/article/details/122846140?spm=1001.2101.3001.6650.3\&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-3-122846140-blog-124536141.pc_relevant_paycolumn_v3\&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-3-122846140-blog-124536141.pc_relevant_paycolumn_v3\&utm_relevant_index=6)  [gcc指定版本](https://blog.csdn.net/b_ingram/article/details/121569398)

ubuntu ：apt install build-essential   【Ubuntu缺省情况下，并没有提供C/C++的编译环境，因此还需要手动安装。开发扩展包】

### 编译链接

***gcc -g -o main xxx.c***

-g debug 模式，包含调试信息，区别于Release 版本

-o 输出结果（可执行文件）   xxx.c  源代码

> 编译 cpp 生成 .o 中间文件，链接生成 可执行文件 和 库文件。
>
> 其中 \[ linux ] .a 是静态库    .so 是动态库     \[windows]  .lib 静态库  .dll动态库

### 动态库和静态库的区别

> 静态库在程序编译时会被连接到目标代码中，程序运行时不再需要静态库；而动态库在程序编译时，不会放到连接的目标代码中，而是在程序运行时被载入，因此在程序运行时还需要动态库的存在。

### [彻底理解链接器](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=Mzg4OTYzODM4Mw==\&action=getalbum\&album_id=1923374391426416642\&scene=173\&from_msgid=2247485635\&from_itemidx=1\&count=3\&nolastread=1\&uin=\&key=\&devicetype=Windows+10+x64\&version=63030532\&lang=zh_CN\&ascene=0\&fontgear=2)

通过拼图这个游戏的类比，我们给出链接器的工作过程：

* 首先，链接器对给定的目标文件或库的集合进行符号决议以确保模块间的依赖是正确的。
* 其次，链接器将给定的目标文件集合进行拼接打包成需要的库或最终可执行文件。
* 最后，链接器对链接好的库或可执行文件进行重定位

#### 第二篇，符号决议

编译器的任务就是把人类可以理解的代码转换成机器可以执行的机器指令，源文件编译后形成对应的目标文件

![](/files/-Mj2GN5Td6KCU4Cbrj7K)

![](/files/-Mj2GQiFz6zcCp66xKsJ)

有同学可能会问，为什么全局变量y\_global\_uninit ，y\_global\_init以及函数fn\_b不可被其它目标文件引用，这是因为这些变量用static修饰过了，在C语言中经static修饰过的函数的函数以及变量都是当前文件私有的，对外部不可见，这里一定要注意。所以static这个关键字的用法就是，如果你认为一个变量只应该被当前文件使用而不暴露给外部，那么你就可以使用static关键字修饰一下。 &#x20;

本质上整个符号表只是想表达两件事：

* 我能提供给其它文件使用的符号
* 我需要其它文件提供给我使用的符号

最终：目标文件 -> **数据段，代码段，符号表**

经过第五篇重定位后  目标文件 -> 数据段，代码段，符号表，.rel.data段，.rel.text

> [nm 命令](https://blog.csdn.net/qq_48322523/article/details/118027964) 查看符号表

#### 第**三**篇，库与可执行文件的生成

静态库

> 可以简单的将静态库理解为由一堆目标文件打包而成， 使用者只需要使用其中的函数而无需关注该函数来自哪个目标文件（找到函数实现所在的目标文件是链接器来完成的，从这里也可以看出，不是所有静态库中的目标文件都会用到，而是用到哪个链接器就链接哪个）。静态库极大方便了对其它团队所写代码的使用。

静态链接是使用库的最简单最直观的形式， 从静态链接生成可执行文件的过程中可以看到，静态链接会将用到的目标文件直接合并到可执行文件当中。

动态库

动态库允许使用该库的可执行文件仅仅包含对动态库的引用而无需将该库拷贝到可执行文件当中。

动态库的使用解决了静态链接当中可执行文件过大的问题。

* load-time dynamic linking(加载时动态链接)

*阶段二：加载可执行文件时依据动态库信息进行动态链接*

由于这阶段一生成的可执行文件中保存了动态库信息，当可执行文件加载完成后，就可以依据此信息进行中动态库的查找以及符号决议了。动态库的链接过程被推迟到了程序启动加载时。（比如libMath.so放到了/usr/lib下，那么使用命令 gcc ... -lMath -L/user/lib ... 进行编译链接）

* run-time dynamic linking(运行时动态链接)

> 所谓run-time(运行时)指的就是从程序开始被CPU执行到程序执行完成退出的这段时间。

run-time dynamic linking 运行时动态链接则不需要在编译链接时提供动态库信息，因此这项任务就留给了程序员，在代码当中如果需要使用某个动态库所提供的函数，我们可以使用特定的API来运行时加载动态库，在Windows下通过LoadLibrary或者LoadLibraryEx，在Linux下通过使用dlopen、dlsym、dlclose这样一组函数在运行时链接动态库。当这些API被调用后，同样是首先去找这些动态库，将其从磁盘copy到内存，然后查找程序依赖的函数是否在动态库中定义。这些过程完成后动态库中的代码就可以被正常使用了。

### makefile 编译

bin、lib、build 均为编译后新生成文件。bin 可执行目录，lib 库的目录 ， build 生成 Makefile等其他

\[root\@464540 build] # rm -rf \*   【可选，因为也会被覆盖】

source ../export\_encs.sh 【导入环境变量，到当前shell 窗口】

cmake ..  生成 build 下的 Makefile

在build 下面 make -j 【在 Makefile 所在路径 make】

![](/files/-MeOVsoCxtxRkziXOBUw)

#### 修改cmake 为cmake3

> which cmake
>
> cd /usr/bin/
>
> ln -sfn cmake3 cmake

#### gcc 版本低可能出现的问题 &#x20;

<img src="/files/fGYX0ieREouLbJo3yB7K" alt="" data-size="line">  [问题原因](https://blog.csdn.net/zxp725167/article/details/122245785)  [ linux strings命令](https://blog.csdn.net/u011068702/article/details/85333453)

### CMake

[CMake 入门实战](https://www.hahack.com/codes/cmake/#)

> 如果修改了CMakeLists.txt，需要cmake
>
> 如果修改了代码，只需要 make

Cmake之CMakeLists.txt [基础](https://blog.csdn.net/u013896064/article/details/82874152)

![](/files/-Mi0L-dVYOQ1TmmLslWs)

![](/files/-Mi0LHfVdMWTQEC_-fL-)

在工程CMakeLists.txt 中，使用add\_definitions()函数[控制代码的开启和关闭](https://blog.csdn.net/fb_941219/article/details/107376017)

> 授权代码为灰色，原因非对外发布版本，不用打开授权过程。

## 重点

### C/C++内存模型

[C/C++内存模型](https://zhuanlan.zhihu.com/p/136287691)

### 常见的内存空间

* 栈空间
* 堆空间
* 内存映射：（  Filesystem为：tmpfs，  eg：/dev/shm ,  内存同磁盘之间的映射 )

![](/files/-Mi0GtWk7c4Mz4xPlfOE)

上图中，1、0  -   0x08048000的内存为受保护空间，程序不能访问。2、【环境变量】每执行一个进程，进程都会拷贝一份环境变量。

【虚拟地址空间】当内存条不是很大的时候，1G，2G，存在虚拟地址到实际内存地址的映射。随着科技的进步，内存的逐步增长。如果4G内存条。一比一映射。（32位机器，2^32 = 4G，即使插入8G内存条，也没用。）

## 语法含义

### char \*argv\[ ]

> 字符指针的数组。
>
> 其中：指向首字符的指针，知道读取到 /0 读取结束。

### int main(int argc, char \*argv \[ ])  { }

Argument count ， Argument Vectors

> 可执行文件传入参数时，同上书写 main 函数。
>
> 编译链接后，可执行文件正常传参。eg: ./ a   x1 x2 x3 。 系统自动解析参数个数，传递给argc，同时各个参数传递 argv\[ ]&#x20;
>
> argv\[0] 为脚本本身文件名字。

### 字符串数组 char \*argv \[ ]

1、变量退化成为指向内存首地址的指针。&#x20;

2、自动打印出字符串数据，直到 \0 截止。

### typedef 类型定义&#x20;

把一个比较长的类型，命名为一个比较好记的短的变量类型。

### 初始化 || 赋值

char str1\[13] = "runoob";    √

str1 = "123";                          ×，  需采用   strcpy( str1 , "Runoob");

### 变量

int b = 4;&#x20;

int \*a = & b;

> 应理解为 （int \*) , *a 为变量名， int \** 是个数据类型，为指向 int 的指针类型

int & c = b;

int & c 为声明一个 b 的别名。（ 带 声明 type ，即定义一个新的变量）&#x20;

int a\[3] , 代表一个  int \[3]  的 数组，a 为变量名。 :tomato:&#x20;

在使用 c 的时候：自动解引用。&#x20;

> 引用的本质是自动解引用的指针。

> C++ 传参一半采用 [引用调用](https://www.runoob.com/cplusplus/cpp-function-call-by-reference.html)。类似 python 语言全部为引用调用。

:cherries: **节省产生临时中间变量内存地址**

单写 & 为取地址操作。

```cpp
cout << "a : " << a << endl;
cout << "c : " << c << endl;
cout << "&c : " << &c << endl;

out:
a : 0x7ffe6cb9c7a0
c : 4
&c : 0x7ffe6cb9c7a0

char a[][10] = {"asdfasd", "wfaw", "dfasdcv", "werfsadf"};
cout << "菜鸟教程: ";
cout << a << endl;
cout << a[1] << endl;

out:
菜鸟教程: 0x7ffc25bad3c0
wfaw
```

* 指针是地址
* cout << 变量（标签） 是 存储的具体值
* 引用，两者兼得。自动解引用为具体值，& 引用为地址 :tomato:&#x20;
* char a\[]\[10]   是 每个都是 char \[10] 的一维数组。要给所存储的最大的初始化定义。保证所有都能存下

### 常量

#### [static 表示的是静态的](https://www.cnblogs.com/kkdd-2013/archive/2013/12/05/3459888.html)

> 不同于局部变量在函数栈针处定义局部变量，在函数结束时，栈空间释放，从而局部变量释放。
>
> static 变量在 static变量区开辟内存。参照-C/C++内存模型-全局变量区（上方）
>
> 全局数据区：全局变量、静态变量、一般常量、字符串常量
>
> 静态变量区。不同于 **堆 栈** 在程序运行时，存在内存溢出导致bug或者程序爆掉的风险。
>
> 静态变量区同VUE的vuex相同道理，全局都能访问的数据区域。联想类内的数据，不用实例化便可以访问的均在 static 关键字 作用下。（同 君波 的聊天心得）
>
> 区分编译时 和 运行时。编译后生成机器码。

####

#### #define （士昂解释：类似宏）&#x20;

\#define LENGTH 10 在编译的时候 LENGTH 被替换为 10，然后编译执行的时候产生常量地址。&#x20;

g++预处理的时候，类的[inline函数是编译的时候](https://www.runoob.com/cplusplus/cpp-inline-functions.html)(下方评论说明解释的更清楚)。

`inline`: 这是一个关键字，它告诉编译器在编译时将函数的定义内联展开到调用它的地方，而不是像常规函数那样生成一个单独的函数体。这样做**可以避免函数调用的开销**，**特别是对于简单的函数**，比如这里的 `Max()` 函数。

#### const 关键字&#x20;

const type variable = value;  会产生可控的常量内存地址

《C++ Primer Plus》第六版 中文版 217页：作为函数传值时，如果**不希望函数内修改原始数据**，可使用const :tomato:&#x20;

#### [关于c语言宏定义中的单#(井号)和双#(井号)](https://www.jianshu.com/p/63fb631ff09f)

### 数据类型

Void 类型，对数据类型不必关心

变量：可以再赋值，在计算机中的物理意义：一个寄存器，临时存储数据。速度非常快&#x20;

常量：不能改变的数据。 相对不能改变，如果我们知道对应地址的位置。可以通过指针改变其值。编译成立的时候，在程序中设定的为静态缓冲区，静态缓冲区受保护，不能随便改动。通过正常的途径修改为不能改变。如果知道内存的物理地址，依然可以改变。常量在声明的时候应该初始化。（被限制的一块空间，一但赋值之后不可以改变，知道地址可以改变）&#x20;

常量同宏定义不同。宏定义为替换，宏定义为常数，在程序中存在，并不存在于某个内存中数据空间，而const 定义的为静态缓冲区数据，通过编译器做的修饰，不能改变

枚举可以看成有限制的整形

### 指针的作用

* 提升执行效率
* 更强的控制力

> 变量传入函数，会在自己的栈针作用域复制一份，现在有了指针，可以直接传递指针，省去变量拷贝的过程&#x20;
>
> 控制力：每个硬件到操作系统层，都会有一个映射地址，通过地址可以访问硬件相关的设备

### 指针的操作

* 对指针自身的操作
* 对所指向内容的操作

> 1、指针加减，访问被指向周围的内存&#x20;
>
> 2、被指向的值的操作

### 指针

type\* *var* &#x20;

> 靠近谁写都可以。风格区分为：
>
> 靠近type 表明 : 这种类型的指针
>
> 靠近变量 表明 : 这个变量是一个指针，具体什么类型不是很关注。靠近type想关注这个指针是什么类型。
>
> &#x20;两种写法对于编译器无区别。

### [typedef](https://www.runoob.com/cplusplus/cpp-data-structures.html) void \* aclrtContext;

[void \* 无类型指针](https://www.runoob.com/w3cnote/c-void-intro.html)：void 指针可以指向任意类型的数据

void \*\&inputBuff                   inputBuff是void\*型的引用参数 :tomato:&#x20;

函数传参传引用，可以直接修改变量。

\*& 就是可以直接修改指针。

而且走的是地址，比复制快一点。

### [二级指针（指向指针的指针）](http://c.biancheng.net/view/2016.html) void \*\* hostPrt&#x20;

CANN   11.8.6 aclrtMallocHost

### 动态内存

new ，执行到那一句的时候在堆上动态开辟内存。C  malloc等动态内存都在堆上。

栈，函数发生调用的时候，开辟内存。函数调用结束，栈针销毁并移动。

```c
char* p = (char*)malloc(10);
// 由于malloc返回 void* 类型指针，所以需要强制转换为 char*
*p = 'a';
*(p+1) = 'b';
free(p);
printf("%s\n", p);
p = NULL;
// 释放掉内存后，由于p依然记录着其地址，为了防止野指针误操作。要在把p置成空指针。
```

### 野指针：指针指了个你不知道是哪的地址

### 内存泄露与野指针

* 不断的向系统申请内存
* 申请的内存不用，也不释放
* 占用别人的内存的称为野指针（参照上述代码：动态内存 -> malloc, free, 但是 p 没有置空）

### 函数指针（ C 语言 ）

> 在C++中就是多态，上层调用同一个函数，但是返回不同的结果。

**返回类型 （\* 指针变量名) (\[形参列表]);**

```cpp
// 教程：
int func(int x);    /* 声明一个函数*/
int (*f)(int x);    /* 声明一个函数指针*/
f = func;           /* 将func函数的首地址赋给指针f*/

// 使用： func 与 func1 为两个不同的函数
int (*f)(int x);
f = func;
f(2);
f = func1;
f(3);
// 结果：将调用不同的函数，c++ 多态基于 c 的函数指针实现。
```

### 引用

[C++ 中创建引用](https://www.runoob.com/cplusplus/cpp-references.html)

变量名称是变量附属在 ***内存位置***  中的 **标签。 >** 该标签所代表的内存地址可以擦写

### class 类

[C++ 指向类的指针](https://www.runoob.com/cplusplus/cpp-pointer-to-class.html)。指向类的指针方式如同指向结构的指针。实际上，类可以看成是一个带有函数的结构。

首先看 python 下属性的分类：&#x20;

| 属性   | 解释                                                                                                                                                         |
| ---- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 实例属性 | <p> 最好在<strong>init</strong>(self,...)中初始化</p><p>内部调用时都需要加上self.</p><p>外部调用时用instancename.propertyname</p>                                                 |
| 类属性  | <p> 在<strong>init</strong>()外初始化<br>在内部用classname.类属性名调用<br>外部既可以用classname.类属性名又可以用instancename.类属性名来调用</p>                                               |
| 私有属性 | <p>1）：单下划线<em>开头：只是告诉别人这是私有属性，外部依然可以访问更改</em><br><em>2）：双下划线</em>\_开头：外部不可通过instancename.propertyname来访问或者更改</p><p>实际将其转化为了\_classname\_\_propertyname</p> |

### [类的前向声明、不完全类型类](https://blog.csdn.net/hlsdbd1990/article/details/46544917)

### using namespace&#x20;

主要是为了区分类和函数，【消歧义】，具体指的哪个类或函数

:tomato: python用包代替了C++的命名空间，只需“import”导入一个包

### const char \*p = "Hello World"

> 能用const的，尽量用const，相当于【性能优化】

char p\[ ] = "hello world"， 等价于 退化为指针的数组首地址赋值给p :cherries:&#x20;

![](/files/-MeOIfU8wKWziig9uYpc)

| 代码                             | 含义         |
| ------------------------------ | ---------- |
| const char \*p = "hello world" | 指针指向的内容不可变 |
| char const \*p = "hello world" | 指针的指向不可变   |

```cpp
int  var[MAX] = {10, 100, 200};
cout << var << endl;
char *p = "hello world";
cout << p << endl;

output：
var:0x7ffd63d90c50
hello world
```

char \* p， char \* 指针 p，使用p，会从指向的首地址开始打印，直到遇到 \0 结束。 :cherries:&#x20;

正常其他类型指针数组，打印 【常量指针】数组的首地址。char \* 是个例外。 :tomato:&#x20;

### for循环i++与++i有什么区别

**++i 性能更高一点。但在for循环中同正常使用在使用上 无 明显不同**

> 原因：i++  先返回 i 再自身 +1，由于 +1 数指 需要存储在 临时变量中，冗余内存。
>
> ++i  ，当前内存值 +1  然后返回。不开辟新的内存冗余
>
> for 中使用 ++i  性能更好。

### 线程&#x20;

[C++11多线程std::thread的简单使用](https://www.cnblogs.com/lifan3a/articles/7538472.html)  ,着重理解：回调函数，join，detach，控制权

join()  作用：等待子线程执行完，再回到主线程。[视频](https://www.bilibili.com/video/BV1Nf4y1U7YC)

普通线程函数调用：[菜鸟教程介绍](https://www.runoob.com/w3cnote/cpp-std-thread.html) 。类内成员函数线程调用：[示例一](https://www.cnblogs.com/tinysun/p/5593702.html)，[示例二](http://www.jyguagua.com/?p=2800) :apple:

调用类成员改成调用函数  <img src="/files/D0LvFmpHF4uU1x6N6f3Y" alt="" data-size="line">  :tada:

### 文件操作

* 文件类型 FILE\* file；
* 打开文件 FILE\* fopen(path, mode);
* 关闭文件 fclose(FILE\*)

```cpp
void createfile(char* filename){
    // open/create file
    FILE* file = fopen(filename, "w");
    if(!file){
        printf("Failed to create file:(%s)\n", filename);
        return
    }
    size_t len = fwrite("aaaaa", 1, 5, file); 
    if(len != 5){
        printf("Failed to write file, (%zu)\n", len);
        fclose(file);
        return
    }
    printf("Successed to write file");
    fclose(file);
    printf("Successed to create file");
}

void read_data(char* filename){

    char buffer[1024] = {0,};
    
    FILE* file = fopen(filename, "r");
    if(!file){
        printf("Failed to open file:(%s)\n", filename);
        return
    }
    size_t len = fread(buffer, 1, 5, file); 
    if(len <= 0){
        printf("Failed to read file\n");
        fclose(file);
        return
    }
    printf("read_data:%s\n", buffer);
    fclose(file);
}
```

### 头文件 ↓

### [#ifndef的用法](https://blog.csdn.net/myyllove/article/details/83067808)

> 如 直播盒子项目中，静态库私有链接ffmpeg，为了固定版本，防止用户因不同的ffmpeg版本而出现结果问题。
>
> 但为了播放，又需要在结构体里拿到 AVPacket。 所以需要声明（去看ffmpeg源码中，AVCODEC\_AVCODEC\_H  这个标志是什么）
>
> &#x20;
>
> \#ifndef AVCODEC\_AVCODEC\_H&#x20;
>
> struct AVPacket;&#x20;
>
> \#endif AVCODEC\_AVCODEC\_H
>
> struct DECODE\_FORMAT\_V2 {&#x20;
>
> &#x20;     ...&#x20;
>
> &#x20;     std::vector\<std::shared\_ptr\<AVPacket>> packet\_data\_vec; // AVPacket源数据
>
> }
>
> 为了不在编译链接的时候检查AVPacket的定义，所以放置到实际项目运行期，继而采用指针。
>
> vector 内存放 AVPacket的指针。

### extern "C"

> 未定义的引用
>
> 1、查看 CMakeLists.txt 中 target\_link\_libraries，是否链接了对应库。
>
> 2、是否在 c++中使用 c 语言头文件，需要加 [extern "C"](https://blog.csdn.net/qq_18144521/article/details/79608355)

```cpp
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}
```

### [安装第三方库，PKG管理](https://www.jianshu.com/p/7eee92d8ad7b)

> 再运行./configure 之前，先设置 环境变量 PKG\_CONFIG\_PATH

###

## gdb调试

### gdb CMakeLists.txt 设置

```cpp
//正式发布才设置
# add_compile_options(-std=c++11 -fPIE -fPIC -fstack-protector-all -Wl,-z,relro,-z,now,-z,noexecstack -pie -O3 -Wall)

//项目根目录下CMakeLists.txt   gdb调试需打开本句，使之make携带调试信息
add_compile_options(-std=c++11 -fPIE -fPIC -fstack-protector-all -Wl,-z,relro,-z,now,-z,noexecstack -pie -O0 -g -Wall)

//正式发布才设置
# set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Set build type to Release")
```

### gdb使用

先运行 [gdb](https://www.bilibili.com/video/BV1Kq4y1D7n2) ./text\_distinguish     ,  然后  r   （run）

| <p>b<br>eg:    b main       b path:13</p> | breakpoint,, 加断点               |
| ----------------------------------------- | ------------------------------ |
| r                                         | run  跑                         |
| <p>n<br>s</p>                             | <p>next （不进函数）<br>s  （进函数）</p> |
| k                                         | kill  debug                    |
| info b                                    | show breakpoint ,看所有断点         |
| d                                         | delete ，删除某个断点                 |
| c                                         | continue，运行到下一个断点处             |
| watch i                                   | watch point，监视某个变量值            |
| bt                                        | 打印函数调用栈，从下向上看                  |
| f0                                        | 到第0                            |
| p                                         | 打印变量                           |
| <p>info r<br>info variables</p>           |                                |
| quit                                      | 退出                             |

![](/files/-MhqpFNywCYvVmgXY5_R)

### vscode 调试

先写CMakeLists.txt <img src="/files/Vh7aaCkGpTjN7Qs8VuqP" alt="" data-size="line">, 然后配置launch.json <img src="/files/oms6xjIsmzasxUPsDvOZ" alt="" data-size="line">

## [Google Test](https://github.com/google/googletest)

### [primer](https://google.github.io/googletest/primer.html)

### 用法注意：

assert 比 expect 更强，直接中断。

## 常用函数

| 函数代码             | 解释       |
| ---------------- | -------- |
| sizeof(a)        | 变量所占字节大小 |
| typeid(a).name() | 变量数据类型   |

## 常用写法

### 格式化输出、输入

include \<stdio.h>

1. 输出
   1. [printf()](https://www.runoob.com/cprogramming/c-function-printf.html)
   2. [sprintf()](https://www.runoob.com/cprogramming/c-function-sprintf.html)    组合    [puts()](https://www.runoob.com/cprogramming/c-function-puts.html)
2. 输入
   1. [scanf()](https://www.runoob.com/cprogramming/c-function-scanf.html) , 用户如果想 输入1,2,3 带逗号，需scanf("%d,%d,%d",\&a,\&b,\&c); 前者参数format需带逗号分割。         scanf("%d%d%d",\&a,\&b,\&c);  问：后面为什么传 \&a。答：因为此函数声明要求传入指针。      声明 int scanf(const char \*format, ...)，char \* 指针，可以传字符串，因为字符串为字符串数组，会退化成char \* 指针。 :tomato: char title\[50];  title 就代表一个长度为50，且每个为char的数组。在作为函数传参数的时候，退化为 char\* 指针。

### 获取路径中的文件名

```cpp
int pos = face_file.find_last_of('/');
std::string file_name(face_file.substr(pos+1));
```

## 相关教程

### [c++精进之路](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzkyODE5NjU2Mw==\&action=getalbum\&album_id=1667018561883570181\&scene=21\&uin=\&key=\&devicetype=Windows+10+x64\&version=63030073\&lang=zh_CN\&ascene=1\&session_us=gh_dd9abbc3a324\&fontgear=2)

## 操作类

### ldd 寻找 程度运行依赖库

> libname.so  后缀为 .so 为具体库
>
> libname.so.0   后缀再跟数字时，.so 变为软连接，指向真正版本号的so文件

## 一些疑问

### [C++与Java的区别](https://blog.csdn.net/kikajack/article/details/85034618)

1. 跨平台(Java). java编译生成字节码再jvm上执行，c++编译生成机器码。
2. 运行速度(C++)
3. 对象是否自动回收(Java)。(Java 中内存的分配和回收由Java虚拟机实现Jvm。Java垃圾自动回收机制，会自动清理引用数为0的对象。C++ 编程时，则需要花精力考虑如何避免内存泄漏。)
4. Java 中，一切皆是类。（）

#### 博客看到的

阅读代码，不怕复杂像屎山，大脑应付这些是完全够用的，大脑的缺陷在于瞬间记忆的记忆空间太少（堆栈小），遇到那种东调用西调用，各种typedef，不停切换源文件的场景，因为这些都要“保存现场”。人脑最拒绝的这些东西，恰好是c++最喜欢干的事情，你写代码不多整几个继承多态，别人会喷你还是回去用c吧

## vscode 显示配置

### vscode 显示红色报错问题

[VSCode配置c\_cpp\_properties.json文件](https://blog.csdn.net/baidu_38634017/article/details/99875321) （.vscode/c\_cpp\_properties.json）

> vscode 默认为老版本，需要修正为新版本

> `"cStandard": "c99", "cppStandard": "gnu++11",`
>
> C 的版本： [K\&R C](https://zh.wikipedia.org/wiki/K%26R_C) • [ANSI C](https://zh.wikipedia.org/wiki/ANSI_C) • [C99](https://zh.wikipedia.org/wiki/C99) • [C11](https://zh.wikipedia.org/wiki/C11) • C18 • [C2x](https://zh.wikipedia.org/wiki/C2x)
>
> C++的版本：[C++ 98](https://zh.wikipedia.org/w/index.php?title=C%2B%2B_98\&action=edit\&redlink=1), [C++03](https://zh.wikipedia.org/wiki/C%2B%2B03), [C++11](https://zh.wikipedia.org/wiki/C%2B%2B11), [C++14](https://zh.wikipedia.org/wiki/C%2B%2B14), [C++17](https://zh.wikipedia.org/wiki/C%2B%2B17), [C++20](https://zh.wikipedia.org/wiki/C%2B%2B20) – C++语言标准

## C++ 转 python 接口 （SWIG）

{% embed url="<http://swig.org/Doc4.0/SWIGDocumentation.html#Python_nn2>" %}

看上述[文档](http://swig.org/Doc4.0/SWIGDocumentation.html#Python_nn2)，里面有些指针之类的没说明白，可以参考[github](https://github.com/iTomstudio/swig_tranform/tree/main/pointer)

遇到的问题：<img src="/files/UU7s7YcTuoKFfeXk1THw" alt="" data-size="line"> ，要链接所有的源代码，swig 转出的结果+ 项目源代码   \[ 32.2.2 Using distutils]

也可以实现自行生成 待链 `extra_objects` 链接进去 。<img src="/files/ZsDzWsDPMNyjSCcXflkq" alt="" data-size="line">

```python
# /* File: setup.py */
#!/usr/bin/env python

"""
setup.py file for SWIG example
"""

from distutils.core import setup, Extension

pylogo_retrv_module = Extension('_pylogo_retrv',
                           sources=['pylogo_retrv_wrap.cxx'],
                           extra_compile_args=['-std=c++11'],
                           extra_objects=['../lib/librmzk_logo_retrv.so']
                           )

setup (name = 'pylogo_retv',
       version = '0.1',
       author      = "SWIG Docs",
       description = """pylogo_retrv py inferface""",
       ext_modules = [pylogo_retrv_module],
       py_modules = ["pylogo_retrv"], 
       )

```

> **/\* File :  install.sh \*/**
>
> \#‘ 编译
>
> swig -c++ -python pylogo\_retrv.i&#x20;
>
> python3 setup.py build\_ext --inplace
>
> \#‘ 安装
>
> mkdir -p ../deploy/py&#x20;
>
> cp *.so py*.py demo.py ../deploy/py
