【C++逆向 - 1】C++函数新特性

内联函数

本质:用函数代码替换函数调用

使用方式:在函数声明和函数定义前加上 inline 关键字

笔者感觉跟C语言中的宏定义差不多,但是内联函数更加“智能”(应该是编译器更加智能)。即使程序员将函数作为内联函数,但是编译器会检查是否满足一些要求,比如是否是递归调用,函数是否过大等。

笔者还是喜欢宏,当然因人而异

引用变量

int a;
int &b = a;
int c = 20;
b = c; // ==> 这里是将 c 的值赋给 b 即 b = a = 20 [其实b的值是a的地址......]

注意:引用变量必须初始化;引用变量不得更换引用对象

本质:b 保存着 a 的地址;每次操作 b 时,会取出其保存的 a 的地址进行操作【是不是感觉跟指针很像,但是指针操作每次还得解引用,所以这里可以看作<指针+自解引用>】

考虑如下代码:

#include <iostream>
#include <fstream>
#include <string>
using namespace std;int add(int a, int b) { return a + b; }
inline int sub(int a, int b) { return a - b; }int main()
{int a = 10;int &b = a;b = 20;cout << &a << " " << &b << endl;cout << a << " " << b << endl;return 0;
}

输出:

0x7ffffa5b781c 0x7ffffa5b781c
20 20

IDA 里面直接识别成的指针:

这里看网上很多人说变量a和变量b的地址是相同的,其实这里我感觉是错误的,变量a和变量b的地址并不相同,因为调试发现变量b保存的是变量a的地址,但是在进行相关操作时会进行特殊处理,比如:

 &b    ==> 其实取的是b保存的a的地址

 b=10 ==> 其实是将变量b保存的a的地址pa取出来,然后执行 [pa] = 10

当然这里说了引用变量保存的是引用对象的地址,跟指针差不多,所以 int &b = a + 3; 是错误的

但好像早期的编译器是允许将表达式作为引用对象的,但是都2023年了,你懂的,其实笔者在函数传参啥的时候还是更喜欢直接用指针,但是后面类的设计,引用就是必不可少的了

当然也要注意当引用作为返回值时,别把局部变量引用返回了,比如如下代码:

#include <iostream>
#include <fstream>
#include <string>
using namespace std;int& func(int &a)
{int b = a;return b;
}int main()
{int a = 10;int &b = func(a);cout << &a << " "  << &b << endl;b = 100;return 0;
}

输出如下:

0x7ffc6e6b2f7c 0
Segmentation fault (core dumped)

默认参数

跟 python 的差不多,就没啥好说的了,注意点:

1)如果 i 位置为默认参数,则 i+x 位置应该都是默认参数

2)如果第 i 个默认参数被赋值,则第 i+x 个默认参数应当都被赋值

函数重载

函数重载条件:

        1)具有不同的函数特征标 ==> 人话就是参数列表不同

        2)函数调用不具有二义性(或多义性)==> 最佳匹配情况下

其实关键的地方在于函数调用的二义性:考虑如下代码

include <fstream>
#include <string>
using namespace std;int func(int a, int b, int c = 10)
{return a + b + c;
}int func(int a, int b)
{return a + b;
}int main()
{int a = func(20, 30, 10);int b = func(20, 30);return 0;
}

这里的函数特征标确实不同,但是在调用函数时具有二义性,即 func(20, 30); 两个函数都可以匹配。如果把 int b = func(20,30); 去掉则可以成功编译

这里我把代码稍微改一下下:仅仅将第二个 func 的第二个参数类型改为 long long

#include <iostream>
#include <fstream>
#include <string>
using namespace std;int func(int a, int b, int c = 10)
{cout << "func 3 argc" << endl;return a + b + c;
}int func(int a, long long b)
{return a + b;
}int main()
{int a = func(20, 30, 10);int b = func(20, 30);return 0;
}

这个时候又可以成功编译,为啥这时不具备二义性呢?这里的二义性是在最匹配的情况下,因为对于 int b = func(20, 30); 来说,30 为 int 类型(在 int 范围内的下常数为 int 类型),所以这里会匹配第一个 func 函数:输出如下

func 3 argc
func 3 argc

函数模板

用法:template <typename TypeName> Function

本质:就是将函数展开

给个demo:

ing namespace std;// typename 可以用 class 关键字代替
template <typename T>
void Swap(T &a, T &b)
{T temp = a;a = b;b = temp;
}int main()
{int a = 10, b = 20;float fa = 20.0, fb = 30.0;Swap(a, b);Swap(fa, fb);cout << a << " " << b << endl;cout << fa << " " << fb << endl;return 0;
}

IDA 中识别如下:

 但是 Swap<float> 还是用的 int(但是问题不大,都是32位的数据类型):

显式具体化

上面的模板实现存在一定问题,比如如果T为数组呢?所以可以具体化一个模板:

#include <iostream>
#include <fstream>
#include <string>
using namespace std;// typename 可以用 class 关键字代替
template <typename T>
void Swap(T &a, T &b)
{T temp = a;a = b;b = temp;cout << "Swap 0" << endl;
}// 具体化
template <> void Swap<float>(float &a, float &b)
{cout << "Swap 1" << endl;
}int main()
{int a = 10, b = 20;float fa = 20.0, fb = 30.0;Swap(a, b);Swap(fa, fb);return 0;
}

输出如下:

Swap 0
Swap 1

如果把函数重载考虑进来,调用关系如下:

        非模板函数>具体化函数>模板化函数 

decltype 关键字

decltype 关键字主要是争对模板类型的,考虑如下代码:

#include <iostream>
#include <fstream>
#include <string>
using namespace std;// typename 可以用 class 关键字代替
template <typename T1, typename T2>
auto add(T1 a, T2 b) -> decltype(a + b)
{decltype(a + b) sum = a + b;return sum;
}int main()
{int a = 10, b = 20;float fa = 20.0, fb = 30.0;int c = add(a, fb);float fc = add(fa, b);cout << c << " " << fc << endl;return 0;
}

这里的问题就是由于 T1 和 T2 的类型我们事先都不知道,所以这里的 sum 和返回类型是啥呢?这里显然也是不知道的,为了解决这里问题,引入了 decltype 关键字

decltype (expression) var;

        1)若 expression 是没用括号的标识符,则 var 类型与该标识符相同

        2)若 expression 是一个函数调用,则 var 类型为函数返回值类型

        3)若 expression 是用括号的左值,则 var 类型为引用类型

        4)若以上都不满足,则 var 类型与 expression 相同

        int a = 10;decltype (a) b;decltype ((a)) c = b;

注意这里的 c 为引用类型,所以记得初始化。 

总结

这里仅仅回顾了一些 C++ 的最基本的知识,并没用深入,注意是为之后的逆向做准备。不熟悉或没接触过 C++ 的读者建议好好的去深入学习下上面所讲的知识,最好自己动手写写代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/225125.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

华为数通方向HCIP-DataCom H12-831题库(多选题:221-240)

第221题 在割接项目的项目调研阶段需要对现网硬件环境进行观察,主要包括以下哪些内容? A、设备的位置 B、ODF位置 C、接口标识 D、光纤接口对应关系 答案:ABCD 解析: 在项目割接前提的项目调研阶段,需要记录下尽可能详细的信息。 第222题 以下哪些项能被正则表达式10*成…

Python 新规范 pyproject.toml 完全解析

多谢&#xff1a;thank Python从PEP 518开始引入的使用pyproject.toml管理项目元数据的方案。 该规范目前已经在很多开源项目中得以支持&#xff1a; Django 这个 Python 生态的顶级项目在 5 个月之前开始使用 pyproject.tomlPytest 这个 Python 生态测试框架的领头羊在 4 个…

智慧幼儿园视频监管方案及实施建议:AI智能技术构建新引擎

一、背景需求 随着科技的快速发展&#xff0c;智慧化监管已成为幼儿园管理的重要趋势。智慧幼儿园监管解决方案通过引入先进的技术手段&#xff0c;提高幼儿园的管理效率&#xff0c;保障幼儿的安全与健康&#xff0c;为家长提供更便捷的服务。为了保障幼儿的安全&#xff0c;…

【通讯录案例-搭建登录界面 Objective-C语言】

一、来看我们这个通讯录案例 1.接下来啊,我们来做这个通讯录案例, 然后呢,做这么一个应用程序啊, 我们第一步呢,先把界面儿搭了, 然后呢,搭之前,简单的来分析一下, 首先呢,这是,中间儿的这一块儿, 1)有个“账户”、“密码”,这一块儿, 这是一个什么控制器,…

OpenCV与YOLO学习与研究指南

引言 OpenCV是一个开源的计算机视觉和机器学习软件库&#xff0c;而YOLO&#xff08;You Only Look Once&#xff09;是一个流行的实时对象检测系统。对于大学生和初学者而言&#xff0c;掌握这两项技术将大大提升他们在图像处理和机器视觉领域的能力。 基础知识储备 在深入…

路由器介绍和命令操作

先来回顾一下上次的内容&#xff1a; ip地址就是由32位二进制数组 二进位数就是只有数字0和1组成 网络位&#xff1a;类似于区号&#xff0c;表示区域作用 主机位&#xff1a;类似于号码&#xff0c;表示区域中编号 网络名称&#xff1a;网络位不变&#xff0c;主机位全为0 …

OpenGL :LearnOpenGL笔记

glfw https://github.com/JoeyDeVries/LearnOpenGL/blob/master/src/1.getting_started/1.1.hello_window/hello_window.cpp #include <glad/glad.h>// 注: GLAD的include文件包含所需的OpenGL头文件(如GL/GL.h) &#xff0c;因此确保在其他需要OpenGL的头文件 (如GLFW…

Java设计模式-适配器模式

目录 一、生活中的适配器例子 二、基本介绍 三、工作原理 四、类适配器模式 &#xff08;一&#xff09;类适配器模式介绍 &#xff08;二&#xff09;应用实例 &#xff08;三&#xff09;类适配器模式注意事项和细节 五、对象适配器模式 &#xff08;一&#xff09…

12.26_黑马数据结构与算法笔记Java

目录 243 图 Floyd Warshall 算法实现2 244 图 Floyd Warshall 算法实现3 245 图 Floyd Warshall 算法实现4 246 图 最小生成树 Prim 247 图 最小生成树 Kruskal 248 图 并查集 1 249 图 并查集 2 250 图 并查集 路径压缩 251 图 并查集 UnionBySize 252 贪心算法 介绍…

【贪心】单源最短路径Python实现

文章目录 [toc]问题描述Dijkstra算法Dijkstra算法的正确性贪心选择性质最优子结构性质 Dijkstra算法应用示例时间复杂性Python实现 个人主页&#xff1a;丷从心 系列专栏&#xff1a;贪心算法 问题描述 给定一个带权有向图 G ( V , E ) G (V , E) G(V,E)&#xff0c;其中每…

uni-app之HelloWorld实现

锋哥原创的uni-app视频教程&#xff1a; 2023版uniapp从入门到上天视频教程(Java后端无废话版)&#xff0c;火爆更新中..._哔哩哔哩_bilibili2023版uniapp从入门到上天视频教程(Java后端无废话版)&#xff0c;火爆更新中...共计23条视频&#xff0c;包括&#xff1a;第1讲 uni…

k8s:kubernets

自动部署、自动扩展和管理的容器化部署的应用程序的一个开源系统 k8s负责自动化运维管理多个容器化程序的集群&#xff0c;是一个功能强大的容器编排工具 可以以分布式和集群化的方式进行容器管理 1.18版本&#xff0c;目前最多的是1.20版本&#xff0c;最新的是1.29版本&am…

走进数字金融峰会,为金融科技数字化赋能

12月20—21日&#xff0c;FSIDigital数字金融峰会在上海圆满召开。本次峰会包含InsurDigital数字保险峰会和B&SDigital数字银行与证券峰会2场平行峰会&#xff1b;吸引了近600位来自保险、银行、证券以及金融科技等行业的领导者和专家齐聚一堂&#xff0c;共同探讨金融业数…

Opencv_CUDA实现推理图像前处理与后处理

Opencv_CUDA实现推理图像前处理与后处理 通过trt 或者 openvino部署深度学习算法时&#xff0c;往往会通过opencv的Mat及算法将图像转换为固定的格式作为输入openvino图像的前后处理后边将在单独的文章中写出今晚空闲搜了一些opencv_cuda的使用方法&#xff0c;在此总结一下前…

2023上海国际计算生物学创新大赛——药物筛选AI算法“凌越”挑战赛,等你来战!

作为一门新兴的交叉学科&#xff0c;计算生物学具有巨大的应用潜力和市场价值。近年来&#xff0c;各国高度重视计算生物学的发展&#xff0c;尝试利用计算生物学的方法和技术破解生物医药行业的难题。 为进一步推动计算生物学发展&#xff0c;落实 《上海市计算生物学创新发展…

强化学习_06_pytorch-TD3实践(CarRacing-v2)

0、TD3算法原理简介 详见笔者前一篇实践强化学习_06_pytorch-TD3实践(BipedalWalkerHardcore-v3) 1、CarRacing环境观察及调整 Action SpaceBox([-1. 0. 0.], 1.0, (3,), float32)Observation SpaceBox(0, 255, (96, 96, 3), uint8) 动作空间是[-1~1, 0~1, 0~1]&#xff0c…

PostgreSQL 可观测性最佳实践

简介 软件简述 PostgreSQL 是一种开源的关系型数据库管理系统 (RDBMS)&#xff0c;它提供了许多可观测性选项&#xff0c;以确保数据库的稳定性和可靠性。 可观测性 可观测性&#xff08;Observability&#xff09;是指对数据库状态和操作进行监控和记录&#xff0c;以便在…

深入探讨Java反射:解析机制与应用场景

当谈及Java编程语言的强大功能时&#xff0c;反射&#xff08;Reflection&#xff09;是一个不可忽视的特性。反射允许程序在运行时检查和操作其自身的结构&#xff0c;这为开发者提供了一种动态获取信息和执行操作的途径。在本篇博客中&#xff0c;我们将深入探讨Java反射的原…

vue-awesome-swiper轮播组件

安装版本&#xff1a;"swiper": "^6.0.0", 安装版本&#xff1a;"vue-awesome-swiper": "^4.1.1", <div class"swiper_conter"><swiper class"swiper" :options"swiperOption" ref"mySw…

SpringBoot 3.2.0 基于Spring Security+JWT实现动态鉴权

依赖版本 JDK 17 Spring Boot 3.2.0 Spring Security 6.2.0 工程源码&#xff1a;Gitee 为了能够不需要额外配置就能启动项目&#xff0c;看到配置效果。用例采用模拟数据&#xff0c;可自行修改为对应的ORM操作 编写Spring Security基础配置 导入依赖 <properties>&l…