6、栈调试
5、可调试性
4、调试器
3、编译器的调试支持
2、操作系统的调试支持
1、CPU调试支持
软件断点
软件断点就是INT3指令
- 机器码为1字节,内存ASCII码为0xCC,经典的“烫烫烫烫”;
- IDE下断点,就是在那条指令的位置插入INT3,或者那个字节替换为0xCC;
- 软件断点没有数量限制,很有灵活性
- 软件断点的局限性:
- 由于软件断点是插入或者修改指令,对于在ROM(只读存储器)中执行的程序比如BIOS或者其他固件程序,无法动态增加软件断点,只能用硬件断点;
- 属于代码类断点(可以让CPU执行到代码段内的某个地址时停下来),所以不适用于数据段和I/O空间;
0、windbg安装
windbg下载
WindowsSDK,中选择下载安装程序,下载下来一个【winsdksetup.exe】,选择第二种Download下载方式,以安装包的形式下载(第一种是在线安装,无法保留安装包)。
点击两次next以后会出现一个界面,这里是选择下载哪些工具,只需要选择第二个【Debugging Tools for Windows】,这个就是需要的windbg。
下载完成后在下载目录中会出现一个文件夹,找到【x64 Debuggers And Tools-x64】和【x86 Debuggers And Tools-x64】点击安装即可。
windbg preview下载
Windbg Preview的功能和windbg的功能是一样的,但是安装更加方便,只需要在Microsoft Store商店中搜索即可。
配置环境变量
- WinDbg访问符号需要使用 symsrv.dll 和 symstore.exe 这两个文件,它们存在与 WinDbg 的执行文件目录下。由于它们直接在执行文件的目录下,所以不需要进行任何的路径配置;
- 在系统环境变量中添加一个新的环境变量
"_NT_SYMBOL_PATH",并将其值设置为
"SRV*c:\mysymbol* http://msdl.microsoft.com/download/symbols",其中“c:”是我们自定义的文件夹路径,windbg在加载符号的时候,会把符号下载到这个目录。
CMD/DOS命令行与批处理
内部命令和外部命令
自定义结构
枚举
enum提供了创建常量的方式,可以替代const。使用#define和const可以创建符号常量,使用enum不仅可以创建符号常量,还能定义新的数据类型。
枚举类型的声明和定义:
1 | //声明,创建一个数据类型,还没有分配存储空间 |
1 | #include <iostream> |
使用细节:
- 枚举值不能做左值;
- 非枚举变量不可以赋值给枚举变量;
- 枚举变量可以赋值给非枚举变量;
enum只是定义了一个常量集合,里面没有元素,在内存中是当作int存储的。sizeof的值为4.
结构体和联合体
结构体与数组有两点不同:结构体可以在一个结构中声明不同的数据类型;相同的结构体可以相互赋值,但数组不行。
联合体(共用体)都是由不同的数据类型成员组成,但联合体同一时间只存放一个被选中的成员。如果对联合体的不同成员赋值,将会对其他成员重写。共用体的用途是当数据项使用多种格式单不会同时使用时,可以节省空间。
结构体和联合体的在内存中是小端存储的,从低地址开始存放。
1 | //结构体 |
结构体中的位字段
有些信息在存储时,并不需要占用一个完整的字节,只需要占用几个或一个二进制位。位了节省存储空间,C预言提供了一种数据结构,称为“位域”或“位段”。
C/C++允许指定占用特定位数的结构成员。字段的类型应该为整形或枚举,接下来是冒号,冒号后面指定使用的位数,且可以使用没有名称的字段来提供间距。每个成员都被称为位字段。赋值时不能超过位域的允许范围,如果超过,仅将等号右侧值的低位赋给位域。
1 | struct reg{ |
存储结构与结构体数据对齐
1 | #include <string.h> |
联合体内部公用一块内存空间,所以内部占用空间按照最大的数据类型来存储,联合体适合内存受限的场景,比如嵌入式系统。也因为这个原因,同一时间只有一个成员有效,写入一个成员时会覆盖其他成员。
空结构体(不含数据成员)的大小是1,不是0。编译器必须要为其分配一个存储空间用于占位。
1 | struct s1 |

- 结构体的每个成员在内存中的起始地址必须满足其类型的对其要求,32位系统要求如下:
- char:任何地址
- short:偶数倍地址
- int:4的整数倍、
- float:4的整数倍
- double:8的整数倍
- 指针:4的整数倍
可以看到,如果结构体中存在一个double,则会按照8字节来对齐。然后所有成员按照顺序依次分配内存,编译器会在成员之间插入填充字节,确保下一个成员满足对齐要求。如果存在结构体嵌套,也按照这个对齐规则,所有结构体中的最大成员值来进行内存对齐。结构体的总大小波许是最大成员对齐值的整数倍。
有一点需要注意,如果结构体中存放了一个数组,数组是按照单个变量一个一个摆放的,不要把数组视为一个整体。
程序是可以修改默认编译选项的,修改结构体内存分配,如果设置为1,那就是连续的内存分配布局:
1 | Visual C++: |