# 汇编的用途

  • 掌握编程语言,代码的本质
  • 破解
  • ...

# 汇编

汇编语言与机器语言 一一对应 ,每一条机器语言指令都有与之 对应 的汇编指令
高级语言可以通过编译得到汇编语言 / 机器语言,但 汇编语言/机器语言 几乎 可能还原成高级语言
Visual studio 在调试下右键 转汇编

9: 	int arrray[] = { 1,2,3 }; //C++ 语言
//汇编-   地址  机器指令 汇编代码
00007FF7BA87191C C7 45 08 01 00 00 00 mov         dword ptr [arrray],1  
00007FF7BA871923 C7 45 0C 02 00 00 00 mov         dword ptr [rbp+0Ch],2  
00007FF7BA87192A C7 45 10 03 00 00 00 mov         dword ptr [rbp+10h],3

高级语言转换过程

  • 编译型语言 (不依赖虚拟机)

C\C++\OC\Swift

  • 脚本语言

Python\JS\PHP

  • 编译型语言 (依赖虚拟机)

Java\Ruby

# Visual studio 2022 常用快捷键

常用快捷键

# 为什么 C++ 支持函数重载

采用 name mangling 或者 name decoration 技术

# 默认参数

  • 默认参数必须从右边开始
  • 如果同时有声明,实现,默认参数只能放在函数声明中

# 指针存储函数名

void func(int v1,void(*p)(int)) // 函数指针
{
	p(v1);
}
void test(int a)
{
	cout << "test(int) - "<< a <<endl;
}
int main(void)
{
	void(*p)(int) = test; // 指针存储函数名
	p(10); 
	func(20,test);
}

# extern "C"

被 extern "C" 修饰的代码会按照 C 语言的方式去编译,用在 C 和 C++ 混合开发

#include  <iostream>
using namespace std;
extern "C" void func() // 使用 C 编译函数重载
{
}
extern "C" void func(int v)
{
}
// 或者
extern "C"  // 使用大括号 C 编译内部
{
	void func()
	{
	}
	void func(int v)
	{
	}
}
int main()
{
	return 0;
}
//“func”: 无法重载具有外部 "C" 链接的

如果函数同时有声明和实现,要让函数声明被 extern "C" 修饰,函数实现可以不修饰 (声明和实现都放,或者放声明处)

# cpp 使用 C 语言开源库

//math.c 文件
int sum(int v1, int v2)
{
	return v1 + v2;
}
int delta(int v1, int v2)
{
	return v1 - v2;
}
#include  <iostream>
using namespace std;
// 或者
extern "C"  // 使用 c 来编译 c 函数
{
	int sum(int v1, int v2);
	int delta(int v1, int v2);
}
int main()
{
	cout << sum(10, 20) << endl;
	cout << delta(30, 20) << endl;
	return 0;
}
/*
输出
30
10
*/
# C 文件写入头文件
//math.h
#pragma once
int sum(int v1, int v2)
{
	return v1 + v2;
}
int delta(int v1, int v2)
{
	return v1 - v2;
}
#include  <iostream>
using namespace std;
// 或者
extern "C"  // 使用 c 来编译头文件
{
#include "math.h" 
}
int main()
{
	cout << sum(10, 20) << endl;
	cout << delta(30, 20) << endl;
	return 0;
}
/*
输出
30
10
*/

# 宏定义

  • C 默认会定义宏 #define _cplusplus , 将此应用到都文件中判断是否为 C 环境来决定是否用 C 编译
#pragma once
#ifdef _cplusplus
extern "C"
{
#endif //_cplusplus
	int sum(int v1, int v2)
	{
		return v1 + v2;
	}
	int delta(int v1, int v2)
	{
		return v1 - v2;
	}
#ifdef _cplusplus
}
#endif //_cplusplus

# #pragma once

  • 我们经常使用 #ifndef,#define,#endif 来防止头文件的内容被重复包含
  • #pragma once 可以防止整个文件的内容被重复包含

# 内联函数与宏

  • 内联函数和宏,都可以减少函数调用的开销
  • 对比宏,内联函数多了语法检测和函数特性

# C++ 有些表达式可以被赋值

int a = 1;
int b = 2;
// 赋值给了 a
(a = b) = 3;
// 赋值给了 b
(a < b ? a : b) = 4;

# const

//const 的含义,const 修饰的是右边的内容
int age = 10;
const int *p1 = &age;
// 修饰 * p1 是常量,而 p1 地址可以改
int const *p2 = &age; // 同 p1,const 可以和类型互换位置
int * const p3 = &age;
//const 修饰右边的内容 p3 是地址常量,不变,而 * p3 可以修改
const int * const p4 = &age;
int const * const p5 = &age;
//p4 和 p5 等价,地址和 * p4,*p5 都是常量不能变

# 引用

  • 引用的本质就是弱化了的指针
  • 一个引用占用一个指针的大小
  • 在 C 语言中,使用指针 (Pointer) 可以间接获取,修改某个变量的值
  • 在 C++ 中,使用引用 (Reference) 可以起到指针类似的功能
    注意:
  • 引用相当于变量的别名 (基本数据类型,枚举,结构体,类,数组等,都可以有引用)
  • 对引用做计算,就是对引用所指向的变量做计算
  • 在定义的事后就必须初始化,一旦指向了某个变量,就不可以再改变,"从一而终"
  • 可以利用引用初始化另一个引用,相当于某个变量的多个别名
  • 不存在 (引用的引用,指向引用的指针,引用数组)
  • 引用存在的价值:比指针更安全,函数返回值可以被赋值
  • const 必须卸载 & 符号的左边,才能算常引用
# const 引用的特点
  • 可以指向临时数据 (常量,表达式,函数返回值等)
  • 可以指向不同类型的数据
  • 作为函数参数时 (此规则也适用于 const指针 )
  • 当常引用指向了 不同类型 的数据时,会产生 临时变量 ,即引用指向的并不是初始化时的那个变量
int age = 10;
	const long& aAge = age;
	age = 30;
00007FF71556184D C7 45 04 0A 00 00 00 mov         dword ptr [rbp+4],0Ah  
	00007FF715561854 8B 45 04             mov         eax,dword ptr [rbp+4]  
	00007FF715561857 89 45 44             mov         dword ptr [rbp+44h],eax  
	00007FF71556185A 48 8D 45 44          lea         rax,[rbp+44h]  
	00007FF71556185E 48 89 45 28          mov         qword ptr [rbp+28h],rax  
	00007FF715561862 C7 45 04 1E 00 00 00 mov         dword ptr [rbp+4],1Eh

#include  <iostream>
#include "math.h"
using namespace std;
/* 
两者引用:机器码相同,汇编相同
*/
int main()
{
	int age = 22;
	int* p = &age;
	*p = 25;
	cout << age << endl;
	int& ref = age;
	ref = 30;
	cout << age << endl;
	return 0;
}
9: 	int& ref = age;
00007FF759091914 48 8D 45 04          lea         rax,[rbp+4]
00007FF759091918 48 89 45 28          mov         qword ptr [rbp+28h],rax
	10: 	ref = 30;
00007FF75909191C 48 8B 45 28          mov         rax,qword ptr [rbp+28h]
00007FF759091920 C7 00 1E 00 00 00    mov         dword ptr [rax],1Eh
   11: 	int* p = &age;
00007FF6CD505214 48 8D 45 04          lea         rax,[rbp+4]  
00007FF6CD505218 48 89 45 28          mov         qword ptr [rbp+28h],rax  
    12: 	*p = 25;
00007FF6CD50521C 48 8B 45 28          mov         rax,qword ptr [rbp+28h]  
00007FF6CD505220 C7 00 19 00 00 00    mov         dword ptr [rax],19h
# 常引用数组
// 数组名 arr 起始就是数组的地址,也是数组首元素的地址
// 数组名 arr 可以看做是指向数组首元素的指针 (int *)
int arr[] = {1,2,3};
// int (&ref)[3] = arr;
int * const &ref = arr; // 常量要用常引用

# 汇编语言

# 汇编语言的种类
  • 8086 汇编 ( 16bit )
  • x86 汇编( 32bit )
  • x64汇编(64bit)
  • ARM 回避那 (嵌入式,移动设备)
  • ...
  • x64 汇编根据编译器不同,两种书写格式

Intel :
AT&T

# AT&T 汇编 VS Intel 汇编

image-20230302073341484

# 寄存器与内存

假设内存中有块红色内存空间的值是 3,现在想把它的值加 1,并将结果存储到蓝色内存空间

  • cpu 首先会将红色内存空间的值放到 EAX 寄存器中 :mov eax , 红色内存空间
  • 然后让 eax 寄存器与 1 相加: add eax,1
  • 最后将值赋值给内存空间: mov 蓝色内存空间, eax
int a = 5;
	a = a + 1;
10: 	int a = 5;
00007FF6E7DA520D C7 45 04 05 00 00 00 mov         dword ptr [rbp+4],5  
    11: 	a = a + 1;
00007FF6E7DA5214 8B 45 04             mov         eax,dword ptr [rbp+4]  
00007FF6E7DA5217 FF C0                inc         eax  
00007FF6E7DA5219 89 45 04             mov         dword ptr [rbp+4],eax

# x64 寄存器 Register

  • RAX(包含EAX)\REX\RCX\RDX :通用寄存器
  • 32bit:EAX\EBX\ECX\EDX :通用寄存器
  • 16bit:AX\BX\CX\DX : 通用寄存器
  • x64 一个寄存器 8 个字节
  • R 开头的寄存器是 64bit 的,占 8 字节
  • E 开头的寄存器是 32bit 的,占 4 个字节

# C++ 内联汇编

#include <iostream>
using namespace std;
int main()
{
	int a = 10;
	// 双下划,C++ 嵌入汇编执行
	__asm
	{
		mov eax, 10
	}
}

# x86 汇编重要指令

  • mov dest,src

将 src 的内容赋值给 dest,类似于 dest = src

  • [地址值]
  • 中括号 [] 里面放的都是内存地址
* `word`是2字节,`dword`是4字节(double word),`qword`是八字节(quad word)
  • call 函数地址
  • 调用函数,并不是真实地址

  • CPU 大小端模式,大部分都是小端模式
    小端模式:高高低低,高字节放高地址,低字节放低地址
    一个变量的地址值,是它所在字节地址中的最小值

  • lea dest , [地址值]

将地址赋值给 dest ,类似 dest = 地址值

  • ret

函数返回

  • xor op1 , op2

op1op2``异或 的结果赋值给 op1 , 类似于 op1 = op1 ^ op2

  • add op1 , op2

类似于 op1 = op1 + op2

  • sub op1 , op2

类似于 op1 = op1 - op2

  • inc op

自增,类似于 op = op + 1

  • dec op

自减,类似于 op = op - 1

  • jmp 内存地址

    • 跳转到某个内存地址去执行代码
    • j 开头的一般都是跳转,大多是带条件的跳转,一般跟 testcmp 等指令配合使用
      参考权威:Intel 白皮书[1]
  • cmp eax , b

cmp 是 ``compare 的简称,比较 eax b` 的值是否相等

# 跳转指令表格

JE, JZ结果为零则跳转 (相等时跳转)ZF=1
equalzero
JNE, JNZ结果不为零则跳转 (不相等时跳转)ZF=0
not equalnot zero
JS结果为负则跳转SF=1
sign (有符号 \ 有负号)
JNS结果为非负则跳转SF=0
not sign (无符号 \ 无负号)
JP, JPE结果中 1 的个数为偶数则跳转PF=1
parity even
JNP, JPO结果中 1 的个数为偶数则跳转PF=0
parity odd
JO结果溢出了则跳转OF=1
overflow
JNO结果没有溢出则跳转OF=0
not overflow
JB, JNAE小于则跳转 (无符号数)CF=1
belownot above equal<
JNB, JAE大于等于则跳转 (无符号数)CF=0
not belowabove equal>=
JBE, JNA小于等于则跳转 (无符号数)CF=1 or ZF=1
below equalnot above<=
JNBE, JA大于则跳转 (无符号数)CF=0 and ZF=0
not below equalabove>
JL, JNGE小于则跳转 (有符号数)SF≠ OF
littlenot great equal<
JNL, JGE大于等于则跳转 (有符号数)SF=OF
not littlegreat equal>=
JLE, JNG小于等于则跳转 (有符号数)ZF=1 or SF≠ OF
little equalnot great<=
JNLE, JG大于则跳转 (有符号数)ZF=0 and SF=OF
not little equalgreat>

# 汇编符号说明

汇编符号说明

# 参考的 C++ 变量名规范

  • 全局变量: g_
  • 成员变量: m_
  • 静态变量: s_
  • 常量: c_

# 类补充

  • struct 默认 public
  • class 默认 private
# 如何利用指针间接访问所指向量的成员变量
  • 从指针中取出对象的地址
  • 利用对象的地址 + 成员变量的偏移量计算出成员变量的地址
  • 根据成员变量的地址访问成员变量的存储空间
  • 类函数默认会被赋值为 ccccccc
  • cc -> int3 : 起到断点的作用
  • 中断:interrupt

# 内存空间的布局

每个应用都有自己独立的内存空间

  • 栈空间

每调用一个函数就会给它分配一段连续的栈空间,等函数调用完毕后会自动回收这段栈空间
自动分配和回收

  • 堆空间

需要主动去申请和释放,在程序运行过程,为了能够自由控制内存的声明周期,大小,会经常使用堆空间的内存

  • 代码区 (段)

用于存放代码

  • 全局区 (数据段)

用于存放全局变量等

# 对初始内存初始化

memset 函数是将较大的数据结构 (比如对象,数组等) 内存清零的比较快的方法

int *p = (int *)malloc(sizeof(int)*10);
//*p=0;// 并不能全部清零,仅前四个字节
memset(p,0,40);// 从 p 地址开始,连续个字节,都设置为 0
Person person;
person.m_id = 1;
person.m_age = 20;
person.m_height = 180;
memset(&person,0,sizeof(person));  // 赋值 person 为零
# new 的初始化
int *p1 = new int;      // 未被初始化
int *p2 = new int();    // 被初始化为 0
int *p3 = new int(5);    // 被初始化为 5
int *p4 = new int[3];    // 数组元素未被初始化
int *p5 = new int[3]();  //3 个数组元素都被初始化为 0
int *p6 = new int[3]{};  //3 个数组元素都被初始化为 0
int *p7 = new int[3]{ 5 } // 数组首元素被初始化为 5,其它元素被初始化为零

# malloc 不会调用类的构造 & 析构函数

#include <iostream>
using namespace std;
struct Person
{
	int m_age;
	Person()
	{
		cout << "Person()" << endl;
	}
	~Person()
	{
		cout << "释放Person()" << endl;
	}
};
int main(void)
{
	Person person; // 会调用默认构造函数
	Person* p = new Person; // 申请空间也会调用默认构造函数
	delete p;
	//malloc 并不调用默认构造函数,
	Person* q = (Person*)malloc(sizeof(Person));
	free(q); // 也不会调用析构函数
	return 0;
}
/*
Person ()
Person ()
释放 Person ()
释放 Person ()
*/

# 成员变量的初始化

  • 全局区默认初始化为 0
  • 如果自定义了构造函数,除了全局区,其他内存空间的成员变量默认都不会被初始化,需要开发人员手动初始化。
#include <iostream>
using namespace std;
struct Person
{
	int m_age;
};
Person g_person;  // 全局变量初始化为 0
int g_age;  // 全局变量默认初始化为 0
int main(void)
{
	//Person person; // 堆空间:没有初始化成员变量
	// 堆空间:没有初始化成员变量
	Person* p0 = new Person;
	// 堆空间:成员变量初始化为 0,// 如果有构造函数则不进行初始化
	Person* p1 = new Person();
	cout << g_age << endl;
	cout << g_person.m_age << endl;
	//cout << person.m_age << endl;
	cout << p0->m_age << endl;
	cout << p1->m_age << endl;
	return 0;
}
/* 输出:
0
0
-842150451
0
*/

# 构造函数的相互调用

struct Person
{
	int m_age;
	int m_height;
	Person() :Person(0,0)
	{
		//Person (0,0)// 不可,此命令汇编申请临时对象,而非调用
	}
	Person(int age,int height):m_age(age),m_height(height)
	{
	
	}
}

# call 汇编机械码

  • call 汇编机械码 E8 直接调用,写死
  • call 汇编机械码 FF 间接调用,可变

# 调用多态性虚表的汇编过程

//调用run
Animal *cat = new Cat();
cat->run();
//ebp-8是指针变量cat的地址
//eax存储的是cat对象的地址
move eax,dword ptr [ebp-8]
//取出cat对象的最前面4个字节(虚表地址)给edx
mov edx, dword ptr [eax]
//跳出虚表的最前面4个字节,取出4个字节赋值给eax
//取出cat::run的函数调用地址给eax
mov eax ,dword ptr [edx+4]
//call cat::run
call eax

# 单例模式 (简)

设计模式的一种,保证某个类永远只创建一个对象

  • 构造函数私有化
  • 定义一个私有的 static 成员变量指向唯一的那个单例对象
  • 提供一个公共的访问单例对象的接口
/* 安全位置小火箭 */
class Rocket
{
private:
    Rocket()
    {
    }
    ~Rocket()
    {
    }
    static Rocket *ms_rocket;
public:
    static Rocket *sharedRocket()
    {
        // 这里要考虑多线程的安全
        if(ms_recket == NULL)
            {
                ms_rocket = new Rocket();
            }
        return ms_rocket;
    }
    static void deleteRocket()
    {
        if(ms_rocket != NULL)
        {
            delete ms_rocket;
            ms_rocket = NULL;
        }
    }
}

# const 成员

  • const 成员:被 const 修饰的成员变量,非静态成员函数
  • const 成员变量
    • 必须初始化 (类内部初始化) 可以在声明的时候直接初始化赋值
    • 非 static 的 const 成员变量还可以再初始化列表中初始化
  • const 成员函数 (非静态)
  • const 关键字写在参数列表后面,函数的声明和实现必须带 const
  • 内部不能修改非 static 成员函数
  • 内部只能调用 const 成员函数,static 成员函数
  • 非 const 成员函数可以调用 const 成员函数
  • const 成员函数和非 const 成员函数构成重载
  • 非 const 对象 (指针) 优先调用非 const 成员函数
  • const 对象 (指针) 只能调用 const 成员函数,static 成员函数

# 拷贝函数

  • 利用已经存在的 car3 对象创建一个 car3 新对象
  • car4 初始化会调用拷贝构造函数
class Car
{
public:
	int m_price;
	int m_length;
	car(int price = 0, int length = 0):m_price(price),m_length(length)
	{
		cout<< "Car(int price = 0,int length = 0)"<<endl;
	}
	// 拷贝构造函数 (会默认生成浅拷贝构造函数)
	Car(const Car &car):m_price(car.m_price),m_length(car.m_length)
	{
		cout <<"Car(const Car &car)"<<endl;
		// m_price = car.m_price;
		// m_length = car.m_length;
	}
	
	void display()
	{
		cout<< "price = " << m_price << " , length="<<m_length << endl;
	}
}
Car car3(100,5);
Car car4(car3);
car4.display();

浅拷贝 (shallow copy): 指针类型的变量只会拷贝地址值
深拷贝 (deep copy): 将指针指向的内容拷贝到新的存储空间

class Car
{
	int m_price;
	char *m_name;
	void copy(const char*name = NULL)
	{
		if(name == NULL)
			return ;
	}
	// 申请新的存储空间
	m_name = new char[strlen(name)+1] {};
	strcpy(m_name,name);
}

# 浅,深拷贝

  • 编译器默认的提供的拷贝是 浅拷贝 (shallow copy)
  • 将一个对象中所有成员变量的值拷贝到另一个对象
  • 如果某个成员变量是个指针,只会拷贝指针中存储的地址值,并不会拷贝指针指向的内存空间
  • 可能会导致堆空间多次 free 的问题
  • 如果需要实现 深拷贝 (deep copy),就需要自定义拷贝构造函数
  • 将指针类型的成员变量所指向的内存空间,拷贝到新的内存空间

# 对象类型的参数和返回值

使用对象类型作为函数的参数或者返回值,可能会产生一些不必要的中间对象,返回引用可避免中间值

# 匿名对象

匿名对象:没有变量名,没有被指针指向的对象,用完后马上调用析构

car();
// 一次性对象,调用完之后立即释放空间

# 隐式构造 / 转换构造

Person p1 = 20;
// 等同于
Person p2(20);
// 都会调用单构造函数
// 隐式构造
Person test2()
{
	return 40; // 隐式构造,会将 40 传递给 Person 单函数对象
}

可以通过关键字 explicit 在定义构造函数时禁止掉隐式构造

# 编译器何时自动生成构造函数

virtual function table 在汇编显示:vftable

  • 成员变量在声明的同时进行了初始化
  • 有定义虚函数
  • 虚继承其他类
  • 包含了对象类型的成员,且这个成员有构造函数 (编译器生成或自定义)
  • 父类有构造函数 (编译器生成或自定义)
  • 对象创建后,需要做一些额外操作时 (比如内存操作,函数调用),编译器一般都会为期生成构造函数

# 内部类

如果将类 A 定义在类 C 的内部,那么类 A 就是一个内部类 (嵌套类)

  • 内部类的特点
    • 支持 public,protected,private 权限
    • 成员函数可以直接访问其外部类对象的所有成员 (反过来不行)
    • 成员函数可以直接不带类名,对象名访问其外部类的 static 成员
    • 不会影响外部类的内存布局

# 局部类

在一个 函数内部 定义的类,称为局部类

  • 局部域仅限于所在的函数内部
  • 其所有的成员必须定义在类内部,不允许定义 static 成员变量
  • 成员函数不能直接访问函数的局部变量 (static 变量除外)
  • 在函数内部定义的类如果未调用类和函数,并不会每次调用函数都调用类

# 类型转换

  • C 语言风格类型转换符
    • (type)expression
    • type(expression)
int a = 10;
double d = (double) a;
double d2 = double(a);
  • C++ 中有 4 个类型转换符
    • static_cast
    • dynamic_cast
    • reinterpret_cast
    • const_cast
    • 使用格式:xx_cast<type>(expression)
int a = 10;
double d = static_cast<double>(a);
# const_cast

一般用于 const 属性,将 const 转换为 非const

#include <iostream>
using namespace std;
class Person
{
};
int main(void)
{
	const Person* p1 = new Person();
	// 实现去除 const 属性的强制类型转换
	Person* p2 = const_cast<Person*>(p1); 
	Person* p3 = (Person*)p1;
	// 汇编语言相同
	return 0;
}
/*
	12: 	Person* p2 = const_cast<Person*>(p1);
00007FF773E2197C 48 8B 45 08          mov         rax,qword ptr [rbp+8]
00007FF773E21980 48 89 45 28          mov         qword ptr [rbp+28h],rax
	13: 	Person* p3 = (Person*)p1;
00007FF773E21984 48 8B 45 08          mov         rax,qword ptr [rbp+8]
00007FF773E21988 48 89 45 48          mov         qword ptr [rbp+48h],rax
*/
# dynamic_cast

一般用于 多态 类型的转换,有 运行安全检测

#include <iostream>
using namespace std;
class Person
{
	virtual void run()
	{
	}
};
class Student : public Person
{
};
class Car
{
};
int main(void)
{
	Person* p1 = new Person();
	Person* p2 = new Student();
	cout << "P1 = " << p1 << endl;
	cout << "P2 = " << p2 << endl;
	// 用于多态类型转换 student 和 Person 没有多态没有虚函数会报错
	// 不太安全,Person 赋值给 student,子类赋值给父类,不安全
	Student* stu1 = dynamic_cast<Student *>(p1); // 不安全
	Student* stu2 = dynamic_cast<Student *>(p2); // 安全
	// 其它方式会把地址完全转过来
	cout << "stu1 = " << stu1 << endl; // 不安全会清空,安全检测
	cout << "stu2 = " << stu2 << endl;
	return 0;
}
/*
P1 = 0000019F7CD6C8B0
P2 = 0000019F7CD6C2C0 
stu1 = 0000000000000000 //p1 赋值失败
stu2 = 0000019F7CD6C2C0 //p2 成功
*/
# static_cast
  • 对比 dynamic_cast,缺乏运行时安全检测
  • 不能交叉转换 (不是同一继承体系的,无法转换)
  • 常用语 基本数据类型 的转换, 非const转成const
  • 适用较广
Person* p1 = new Person();
	Car* c1 = dynamic_cast<Car*>(p1);
	// 报错,交叉转换不允许 car 和 Person 没有任何关系
	//Car* c2 = static_cast<Car*>(p1);
	// 基本类型转换
	int a = 10;
	double d = static_cast<double>(a);
	return 0;
# reinterpret_cast
  • 属于比较 底层的强制转换 ,没有任何类型检查和格式转换, 仅仅是简单的二进制数据拷贝
  • 可以交叉转换
  • 可以将指针和整数相互转换
#include <iostream>
using namespace std;
int main(void)
{
	int a = 10;
	// 小端模式从后面开始读
	// 二进制 0000 1010 0000 0000 0000 0000
	// 十六进制: 0A 00 00 00
	//int a = 10;
	//double 八个字节,double 和 int 并不能简单的二进制 copy
	// 00 00 00 00 00 00 24 40
	double d = reinterpret_cast<double&>(a);
	// 二进制纯 copy
	cout << "a= " << a << endl;
	cout << "d= " << d << endl;
	return 0;
}
/*
a= 10
d= 8.33713e+80
*/

参考资料:《30 小时快速精通 C++ 和外挂》


  1. https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html ↩︎