编程语言-Cpp
基础知识
关键字
static
const
extern
volatile
register
auto
virtual
delete
default
override
final
explict
friend
内存分布
代码区(Text)
编译器编译源码后集中存放机器指令的区域,需要系统加载到指定内存地址(虚拟地址)才能够正常运行。
存储内容:CPU 执行的机器指令。
特点:只读且共享(如果有多个进程运行同一个程序,它们可以共享内存中的指令段)。
栈区(Stack)
栈由编译器自动分配和释放。它遵循“后进先出”(LIFO)的原则。x86一般向低地址增长。
存储内容:局部变量、函数参数、返回地址。
特点:速度极快,空间有限(通常只有几 MB)。
生存期:随着函数调用的结束,栈帧会被弹出,内存自动回收。
堆区(Heap)
堆是由程序员手动控制的区域。在 C++ 中,我们通过 new 或 malloc 申请,通过 delete 或 free 释放。x86一般向高地址增长。
- 存储内容:动态分配的对象或数组。
- 特点:空间大(受限于虚拟内存),速度比栈慢,容易产生内存碎片。
- 生存期:由程序员控制。如果你忘记释放,就会导致内存泄漏。
常量区(Constant)
存储内容:常量字符串(如
"Hello World")以及被const修饰的全局变量。特点:只读。尝试修改这部分内存会导致运行时的访问冲突。
全局/静态存储区(Global)
这一块区域在程序启动时分配,程序结束时释放。
.data 段:存储已初始化的全局变量和静态变量。
.bss 段:存储未初始化(或初始化为 0)的全局变量和静态变量。
小知识:BSS 段不占用可执行文件实际的大小,只记录所需的空间,在加载时由 OS 清零。
示例代码
Makefile1
2
3
4
5
6
7
8
9
10
11
12
13
14TARGET ?= main
RUN_ARGS ?=
all: $(TARGET)
$(TARGET): main.cpp
@g++ -g -O0 -o $@ $<
run: all
@./$(TARGET) $(RUN_ARGS)
clean:
@rm -f $(TARGET)
.PHONY: all
main.cpp1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <iostream>
using namespace std;
const char *str1 = "Hello world1";
const char *str2 = "Hello world2";
int main(int argc, const char *argv[]) {
cout << "str1 " << &str1 << " " << str1 << endl;
cout << "str2 " << &str2 << " " << str2 << endl;
int v1;
cout << "v1 " << &v1 << endl;
int v2;
cout << "v2 " << &v2 << endl;
auto p1 = new int();
cout << "p1 " << p1 << endl;
auto p2 = new int();
cout << "p2 " << p2 << endl;
return 0;
}
输出信息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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93$ make run
str1 0x563ce0a0d010 Hello world1
str2 0x563ce0a0d018 Hello world2
v1 0x7ffe5fff6530
v2 0x7ffe5fff6534
p1 0x563cfced32c0
p2 0x563cfced32e0
$ readelf -S main
There are 37 section headers, starting at offset 0x7b20:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .interp PROGBITS 0000000000000318 00000318
000000000000001c 0000000000000000 A 0 0 1
[ 2] .note.gnu.pr[...] NOTE 0000000000000338 00000338
0000000000000030 0000000000000000 A 0 0 8
[ 3] .note.gnu.bu[...] NOTE 0000000000000368 00000368
0000000000000024 0000000000000000 A 0 0 4
[ 4] .note.ABI-tag NOTE 000000000000038c 0000038c
0000000000000020 0000000000000000 A 0 0 4
[ 5] .gnu.hash GNU_HASH 00000000000003b0 000003b0
0000000000000028 0000000000000000 A 6 0 8
[ 6] .dynsym DYNSYM 00000000000003d8 000003d8
0000000000000180 0000000000000018 A 7 1 8
[ 7] .dynstr STRTAB 0000000000000558 00000558
000000000000019b 0000000000000000 A 0 0 1
[ 8] .gnu.version VERSYM 00000000000006f4 000006f4
0000000000000020 0000000000000002 A 6 0 2
[ 9] .gnu.version_r VERNEED 0000000000000718 00000718
0000000000000060 0000000000000000 A 7 2 8
[10] .rela.dyn RELA 0000000000000778 00000778
0000000000000150 0000000000000018 A 6 0 8
[11] .rela.plt RELA 00000000000008c8 000008c8
00000000000000a8 0000000000000018 AI 6 24 8
[12] .init PROGBITS 0000000000001000 00001000
000000000000001b 0000000000000000 AX 0 0 4
[13] .plt PROGBITS 0000000000001020 00001020
0000000000000080 0000000000000010 AX 0 0 16
[14] .plt.got PROGBITS 00000000000010a0 000010a0
0000000000000010 0000000000000010 AX 0 0 16
[15] .plt.sec PROGBITS 00000000000010b0 000010b0
0000000000000070 0000000000000010 AX 0 0 16
[16] .text PROGBITS 0000000000001120 00001120
0000000000000385 0000000000000000 AX 0 0 16
[17] .fini PROGBITS 00000000000014a8 000014a8
000000000000000d 0000000000000000 AX 0 0 4
[18] .rodata PROGBITS 0000000000002000 00002000
000000000000003c 0000000000000000 A 0 0 4
[19] .eh_frame_hdr PROGBITS 000000000000203c 0000203c
0000000000000044 0000000000000000 A 0 0 4
[20] .eh_frame PROGBITS 0000000000002080 00002080
00000000000000ec 0000000000000000 A 0 0 8
[21] .init_array INIT_ARRAY 0000000000003d60 00002d60
0000000000000010 0000000000000008 WA 0 0 8
[22] .fini_array FINI_ARRAY 0000000000003d70 00002d70
0000000000000008 0000000000000008 WA 0 0 8
[23] .dynamic DYNAMIC 0000000000003d78 00002d78
0000000000000200 0000000000000010 WA 7 0 8
[24] .got PROGBITS 0000000000003f78 00002f78
0000000000000088 0000000000000008 WA 0 0 8
[25] .data PROGBITS 0000000000004000 00003000
0000000000000020 0000000000000000 WA 0 0 8
[26] .bss NOBITS 0000000000004040 00003020
0000000000000118 0000000000000000 WA 0 0 64
[27] .comment PROGBITS 0000000000000000 00003020
000000000000002d 0000000000000001 MS 0 0 1
[28] .debug_aranges PROGBITS 0000000000000000 0000304d
0000000000000030 0000000000000000 0 0 1
[29] .debug_info PROGBITS 0000000000000000 0000307d
00000000000024b3 0000000000000000 0 0 1
[30] .debug_abbrev PROGBITS 0000000000000000 00005530
00000000000005d0 0000000000000000 0 0 1
[31] .debug_line PROGBITS 0000000000000000 00005b00
00000000000001ab 0000000000000000 0 0 1
[32] .debug_str PROGBITS 0000000000000000 00005cab
0000000000001242 0000000000000001 MS 0 0 1
[33] .debug_line_str PROGBITS 0000000000000000 00006eed
0000000000000289 0000000000000001 MS 0 0 1
[34] .symtab SYMTAB 0000000000000000 00007178
00000000000004b0 0000000000000018 35 21 8
[35] .strtab STRTAB 0000000000000000 00007628
0000000000000387 0000000000000000 0 0 1
[36] .shstrtab STRTAB 0000000000000000 000079af
000000000000016a 0000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
D (mbind), l (large), p (processor specific)
指针与引用
右值引用
struct与class
struct内存分布
class内存分布
sizeof与strlen
对象的三大特性
封装
继承
多态
虚函数实现动态多态的原理
虚函数与纯虚函数的区别
类的访问权限
private
protected
public
类的成员函数
构造函数
析构函数
赋值函数
拷贝函数
移动构造函数
拷贝构造函数
深拷贝
浅拷贝
类的运算符函数
成员函数
构造函数 析构函数 拷贝构造函数
移动构造函数 移动赋值运算符
运算符(= & + - * / ++ – += -= [] () << >> …)
静态成员函数 static
只读成员函数 const
虚函数 纯虚函数 virtual =0
不可调用函数 =delete
默认类函数 =default
覆写函数 防止覆写函数 override final
单参数构造函数显示转换 explict
友元函数 friend
枚举
类型转换
static_cast
dynamic_cast
const_cast
reinterpret_cast
静态与多态
重写
重载
模板
标准库
std
std::move函数
智能指针
auto_ptr
unique_ptr
shared_ptr
weak_ptr
STL容器
迭代器
迭代器原理
迭代器失效
vector
list
map
set
map与unordered_map
set与unordered_set
vector与list
容器空间配置器
编写技巧
预处理宏自动生成
字符串化
C语言宏定义可以有一些特殊用法:
- #: 预处理阶段,将宏参数转化为字符串
- ##: 预处理阶段,将两个标识符拼接成一个标识符
具体步骤:
- 将需要的枚举名放到固定的地方统一管理,使用特别的宏函数
ENUM_OR_STRING封装,例如枚举文件signal_list.gen
1 | // signal_list.gen |
- 定义宏函数
ENUM_OR_STRING,使用枚举文件声明枚举
1 | // signal_id.h |
- 定义宏函数
ENUM_OR_STRING,实现获取枚举字符串方法
1 |
|
常见问题
变量初始化顺序
1 | [build] /root/project/prj3/xxxx2c/include/MODE2C/DEV/CtxUtility.h: In constructor ‘MODE2C::DEV::CtxComponent::CtxComponent(MODE2C::DEV::NodeArchitecture&, MODE2C::DEV::ASTBasePtr, MODE2C::DEV::NodeComponent&)’: |
这几句告警说的是变量顺序问题,英文大意为:
成员变量
mpnewInstance将会在mpexistingInstance之后初始化,当调用类构造函数CtxComponent::CtxComponent进行初始化时。
解决方案:调整相关变量初始化顺序