当前位置: 首页 > news >正文

盘一盘C++的类型描述符(一)

前言

C++的类型描述方式是从C语言继承来的,并且进行了扩充(例如引用、非静态成员函数、模板实参等)。但由于C语言中的类型描述方式就略微有点「反人类」,再经C++扩展后就有点「反碳基生物」了~

是的,当我第一次看到这种描述符的时候,我也觉得能写出这玩意的肯定不是碳基生物……没准是用偏硅酸盐合成的新型物种……

void (Test::*(Test::*const &)() const)() const

更离谱的是,上面这种类型如果通过type_traits以后会变成什么?

using type = void (Test::*(Test::*const &)() const)() const;
std::remove_const_t<type>; // 这又是个啥类型呢?

好吧,但愿这个引子可以让读者产生兴趣,而不是劝退(才怪……)。

但,真的理解了以后,emmm…确实也是人类能理解的吧(或许当我理解它的那一刻,我的体内就已经在合成SiO32−SiO_3^{2-}SiO32了吧……【手动捂脸】)

因此,本篇就来盘一盘C++的类型描述符,带读者由浅入深,一步一步征服它。

先从指针类型说起

指针类型其实是指针的默认解类型

首先我们应当知道,「指针类型」本身,指的就是「用于保存内存地址的变量类型」。而对于内存地址来说,都是一样的(不存在XXX类型的内存地址这种说法)。所以,照理说,「指针类型」应该就都是一种类型,表示这种类型的数据,应当解释为内存地址。我们这里暂且把这种指针类型起名为ptr_t

void Demo() {using ptr_t = void *; // 可以先忽略这一行int a;double b;ptr_t p1 = nullptr; // 空地址ptr_t p2 = &a; // 用于保存a的地址ptr_t p3 = &b; // 用于保存b的地址ptr_t p4 = &p2; // 用于保存p2的地址
}

只是,通常情况下,我们仅仅拿到一个内存地址是没什么意义的(难道只是为了把它打印出来吗?),拿这个内存肯定是为了操作这个内存上的数据,而我们只知道这个数据的地址是不够的,我们还得知道,要用什么样的方式来解释存在这里的数据,也就是「指针的解类型」。例如,我们「用int的方式来解p2指针」,也就是从p2的值所表示的地址处开始,向高地址方向取sizeof(int)个字节的数据,按照小端序组装起来,并把首位认为是符号位,然后读出(或者写入)这个整数。比如说把读出来的这个值赋给另一个变量y,代码写作:

int y = *(int *)p2; // 表示把p2这个指针,按照int方式解出来,得到的值赋值给y

但如果每次都去指定指针的解类型,会很麻烦,所以我们就希望能给这个指针添加一个「默认解类型」,也就是说,在定义这个指针类型的时候,给它指定一个默认的解类型,如果后续不指定类型,直接解指针的话,就用这种默认的解类型。

从C++的语法上来说,类型+星号,表示定义一个指定了默认解类型的指针类型。比如说:

int *p5 = &a; // p5是指针类型,默认解类型是intint z = *p5; // 没有指定解类型的时候,选用默认的解类型,也就是int类型

同理,如果「默认解类型」是「一个指针类型」的话,也是一样的:

ptr_t *p6 = &p5; // p6的默认解类型是指针类型ptr_t p7 = *p6; // 解出来就是ptr_t类型,所以p7也是指针类型
// 但是因为ptr_t是未指定解类型的指针类型,所以解的时候必须要指定解类型
int w = *(int *)p7;

那么,如果我还希望解出来的指针类型也含有默认解类型的话,就可以用「默认解类型」是「一个指定了『默认解类型』的指针」的指针类型:

int **p8 = &p5; // p8的默认解类型是int *类型
// 所以对p8直接解指针后,得到的就应该是int *类型
int *p9 = *p8;
// 而p9是默认解类型为int的指针类型,解指针后得到int类型
int t = *p9;

上面的例子想表明的是:

  1. 只要是指针类型,都是用来保存内存地址的,也就是说它的值仅仅表示地址。
  2. 指针类型中,星号前面的部分表示的「指针的默认解类型」。
  3. 多级指针本质是「默认解类型为『指针类型』的指针类型」,所以无论前面的类型多么复杂,它都属于这个指针的默认解类型,而不影响这个指针本身。

泛型指针类型其实是无默认解类型的指针类型

再回头来看看刚才这个ptr_t,刚才有一句我让大家先忽略的那一行定义:

using ptr_t = void *;

我们希望表示的是「不含默认解类型」的指针类型,按照语法,默认解类型是T的指针类型就是T *,那么「不含」默认解类型的,就可以理解为默认解类型是「空」的,自然就是void *

所以我们常说的「泛型」指针,之所以能「泛」,其实就是因为,没有指定默认解类型而已,并没有什么稀奇的。

指针类型转换本质是指针默认解类型转换

既然我们知道了指针类型其实表示的是它的默认解类型,那么指针类型的转换自然是表示它默认解类型的转换了:

void *p = &a;
int *p2 = (int *)p; // void *转换为int *,其实就是默认解类型从空变为int

所以前面例子中我们「指定解类型」的解指针方式,本质就是把指针转换为「默认解类型是对应类型」的指针类型,再去解指针:

int y = *(int *)p; // 其实是把p转换为int *类型,再解指针,自然得到int类型

那么,把「含有默认解类型的指针类型」转换为「不含默认解类型的指针类型」应当是一种较为安全的静态转换,因此,我们使用static_cast来代替之前C风格的转换:

int *p = &a;
void *p2 = static_cast<void *>(p); // int * → void *

另外,上面这种转换也支持隐式转换:

int *p = &a;
void *p2 = p; // int * → void *

同理,给「不含默认解类型的指针类型」赋予一个默认解类型,变为「含有默认解类型的指针类型」也是一种较为安全的静态转换,所以同样使用static_cast

void *p = &a;
int *p2 = static_cast<int *>(p); // void * → int *

不过这种转换不支持隐式转换,必须强转。

而「默认解类型为A的指针类型」转换为「默认解类型是B的指针类型」(这里的A,B都不是void)则被认为是一种相对不安全的转换,因为改变指针的默认解类型相当于「重新解释了」指针所指数据的含义。因此,这里要使用reinterpret_cast

int *p = &a;
char *p2 = reinterpret_cast<char *>(p); // int * → char *

const修饰的指针

const关键字在C/C++中并不是代表真正的常量,而是应当理解为read-only,也就是只读。用const修饰的类型不可被修改,只能读取。

而对于指针来说,指针本身既然是一种数据类型,那么也就存在「只读的指针类型」。另一方面,指针的默认解类型也可能是一种只读类型,所以,我们主要是要区分这个const修饰的是指针类型本身,还是指针的默认解类型中的类型。

int *p1; // 指针本身可变,默认解类型是int
const int *p2; // 指针本身可变,默认解类型是const int
int *const p3; // 指针本身不可变,默认解类型是int
const int *const p4; // 指针本身不可变,默认解类型是const int

当我们理解了何为指针的解类型后,其实就很好判断了。如果const出现在解类型中,那么它与指针本身是否可变无关,只有在修饰指针本身的时候,才表示这个指针变量是个只读变量。

而在指针类型的表达式中,我们首先应当找到那个「特殊的星号」,由这个星号隔开,其余的内容都是解类型。

比如在int *const p3中,星号只有一个,自然就是那个特殊的(或者说最内层的),星号前面(外面)的都是解类型,而这个const出现在特殊型号的右边(内部),因此,它修饰的是这个变量本身,那么我们就说p3是只读类型。而剩下的部分,是它的解类型,也就是int

同理,在const int *p2中,也只出现了一个星号,它就是特殊的那个。星号后面没有const修饰,所以p2是可变的,而它的解类型是const int,也就是说这里的const修饰的是解类型。

C++中提供了一个模板工具std::remove_const,用于去掉类型的const修饰,这里要注意的是,它去掉的是类型本身的const,而跟解类型是完全没有关系的,会原样保留,比如说:

std::remove_const_t<const int *>; // const int *
std::remove_const_t<int *const>; // int *
std::remove_const_t<const int *const>; // const int *

那么,对于多级指针呢?同理,我们需要找到特殊的星号(最内层的星号),由他隔离开,外边都是解类型。

int *const *p1; // p1可变,解类型是int *const 
int **const *p2; // p2可变,解类型是int **const
const int **p3; // p3可变, 解类型是const int *
int *const *const p4; // p4不可变,解类型是int *const 

所以,它们如果去掉const也是同理,只会去掉那个修饰变量本身的const,而解类型不会改变:

std::remove_const_t<int *const *>; // int * const *
std::remove_const_t<int **const *>; // int **const *
std::remove_const_t<const int **>; // const int **
std::remove_const_t<int *const *const>; // int *const *

总结就是一句,找到最内层的星号(目前的例子其实都是最右边的星号),由它分隔,外面(目前例子都是左边)都表示解类型,与变量本身无关,里面(目前例子都是右边)才是修饰变量本身的,如果出现了const,就表示变量本身不可变。

后面的章节将会介绍真正的「里面」和「外面」并不符合前面的「右边」和「左边」规律的例子。

数组类型

单纯的数组类型

笔者采访过一些C++程序员(以C++为主要开发语言的从业者),惊奇地发现有一多半的人都不了解「数组类型」。尽管他们可能天天见、天天使用,但从来没有意识到这种类型的存在形态。

举个例子来说:

int arr[] {1, 2, 3};

请问arr是什么类型?数组类型?指针类型?int *类型?

揭晓答案,arrint [3]类型,解释为,含有3个int元素的数组类型。我相信大家对「数组类型」肯定不陌生,也能解释清楚它的元素类型、个数等。但是乍一看到这个int [3]类型,还是有很多人会懵圈的。

的确,我们并不容易注意到arr的类型就是int [3],这主要是因为,C++的数组类型通常情况下只会在定义的时候用到,之后就全部改用指针和偏移量去操作了。

那么现在就请读者知晓,数组类型本身包含了「元素类型」和「元素个数」这两个因素的。它是独立存在一种类型,并不是指针/结构体/整数等的语法糖。只不过,数组类型可以隐式转换为首元素的指针类型:

auto p = arr; // p是int *类型
// 也就是等价于
int *p = (int *)arr;

所以我们一定要清楚,数组是数组,指针是指针,这是两种不同的类型,只是可以隐式转换而已。要想验证也很简单,用std::is_same来验证,或者直接通过sizeof也可以间接验证:

int arr[] {1, 2, 3};
auto p = arr;std::is_same_v<decltype(arr), decltype(p)>; // false
std::is_same_v<int [3], int *>; // false// 假设64位环境
sizeof(arr); // 12
sizeof(p); // 8
sizeof(int [3]); // 12
sizeof(int *); // 8

识别清数组类型,会对我们在模板实例化时避坑有很大帮助。比如说下面的写法就是有问题的:

std::shared_ptr<int *> p = new int[5];

因为p被识别为int *类型的智能指针,那么在p析构时,只会调用delete方法,而不是delete [],使得这片堆空间没有被正确释放。

正确的写法是:

std::shared_ptr<int[]> p = new int[5]; // 要用数组类型,而不是指针类型

再比如,模板的自动类型推导中,如果传入数组也会被识别为数组类型:

template <typename T>
struct Test {Test(const T &t) {}
};void Demo() {int arr[] {1, 2, 3};auto p = arr;Test t1{arr}; // t1是Test<int[3]>类型Test t2{p}; // t2是Test<int *>类型
}

const数组类型

那么,是否存在不可变数组类型呢?我们知道,数组一旦确定,它的元素类型不可变,元素个数也不可变,所以但从数组的两个因素来讲,所有的数组都是不可变的,因此也就不存在所谓可变还是不可变数组类型。

那么对于数组来说,唯一可以控制是否可变的就是元素类型,因此,只存在const T [N]类型,而不存在类似于T (const) [N]之类的。注意,T const [N]const T [N]等价,const都是修饰元素类型的。

既然const是修饰元素类型的,那么它隐式转换为指针后,这个const也一定修饰的是解类型,而不是指针本身:

const int arr[] {1, 2, 3};
auto p = arr; // p的类型是const int *

数组指针类型

数组指针类型其实就是指「默认解类型是数组类型的指针类型」。一定要注意,这跟「数组首元素指针类型」是不同的!数组类型不能转化成它,而是要通过取地址运算得到:

int arr[] {1, 2, 3};
auto p = &arr; // p的类型是int (*)[3]

这里我们不得不引出C/C++中类型描述符的一大绕不开的「缺陷」了,那就是类型描述符并不一定是从左向右,而是可能从里向外。前面章节我们提到过「内部」和「外部」的说法,也是为了跟这种类型描述符的特点相对应。

从「数组类型」开始,就已经符合这种由内向外的描述方式了:

int arr[3];

arrint [3]类型,但并没有写作int[3] arr而是写作了int arr[3]。我们注意到,变量名被夹在了类型描述符的中间。对于更复杂的这种类型描述方式来说,我们需要由内向外来解释,首先要找到变量名,然后逐层向外来阅读。例如:

int (*p)[3];

首先找到变量名p,由括号限定的最内层有一个型号,表示p本身是一个指针。那么再向外一层则表示指针的解类型,这里它的解类型是int [3]。所以综合来说,p是一个解类型为int [3]类型的指针,也就是我们通常所说的「数组指针」类型。

与之对应的一个容易搞混的是:

int *q[3];

同样先找到变量名q,向外一层则是数组,右边表示数组元素个数,左边表示数组元素类型。所以q是数组,元素类型是int *,也就是我们通常说的「指针数组」。

【第二篇待更】

相关文章:

盘一盘C++的类型描述符(一)

前言 C的类型描述方式是从C语言继承来的&#xff0c;并且进行了扩充&#xff08;例如引用、非静态成员函数、模板实参等&#xff09;。但由于C语言中的类型描述方式就略微有点「反人类」&#xff0c;再经C扩展后就有点「反碳基生物」了~ 是的&#xff0c;当我第一次看到这种描…...

Peppol的发展史和基本框架

Peppol&#xff08;Pan-European Public Procurement Online&#xff09;是欧洲区域内的一个跨境公共采购电子商务平台试点项目&#xff0c;由欧盟委员会和Peppol联盟成员国共同资助建立&#xff0c;旨在通过制定标准化框架&#xff0c;推动欧盟成员国在公共采购相关的电子目录…...

Linux-GCC介绍+入门级Makefile使用

前言&#xff08;1&#xff09;我们都知道&#xff0c;在Linux中编译.c文件需要使用gcc -o .c文件的指令来将C文件变成可执行文件。但是我们有没有发现&#xff0c;如果我们需要编译大一点的工程&#xff0c;后面需要加上的.c文件是不是太多了&#xff1f;感觉非常的麻烦。&…...

iOS(一):Swift纯代码模式iOS开发入门教程

Swift纯代码模式iOS开发入门教程项目初始化&#xff08;修改为纯代码项目&#xff09;安装第三方库&#xff08;以SnapKit库为例&#xff09;桥接OC库&#xff08;QMUIKit&#xff09;封装视图并进行导航跳转示例&#xff1a;使用 TangramKit 第三方UI布局库应用国际化添加 R.s…...

IDEA+Python+Selenium+360浏览器自动化测试

环境配置前提&#xff0c;见文章https://mp.csdn.net/mp_blog/creation/editor/new?spm1001.2101.3001.4503下载360浏览器&#xff0c;并下载对应版本的chromedriver.exe&#xff0c;下载地址http://chromedriver.storage.googleapis.com/index.html下载好360浏览器&#xff0…...

运输层概述及web请求

运输层 运输层概述 运输层向高层用户屏蔽了下面网络核心的细节&#xff08;如网络拓扑、所采用的路由选择协议等&#xff09;它使应用进程看见的就好像是在两个运输层实体之间有一条端到端的逻辑通信信道&#xff1b; 根据需求不同&#xff0c;运输层提供两种运输协议 面向连…...

python与pycharm从零安装

python&#xff08;解释器&#xff09;下载地址&#xff1a;Welcome to Python.orgpycharm&#xff08;编译器&#xff09;下载地址&#xff1a;PyCharm: the Python IDE for Professional Developers by JetBrains一、python的下载与安装到官网后根据步骤下载安装包后&#xf…...

叠氮试剂943858-70-6,Azidobutyric acid NHS ester,叠氮-C3-活性酯

1、试剂基团反应特点&#xff08;Reagent group reaction characteristics&#xff09;&#xff1a;Azidobutyric acid NHS ester具有叠氮化物和NHS酯端基。西安凯新生物科技有限公司供应的叠氮化物可以与炔烃、DBCO和BCN进行铜催化的点击化学反应。NHS酯可以与胺基反应&#x…...

pycharm激活虚拟环境时报错:无法加载文件activate.ps1,因为在此系统上禁止运行脚本,Windows10系统

问题&#xff1a; ii_env\Scripts\activate : 无法加载文件 F:\gitlab\AutoFrame\ii_env\Scripts\Activate.ps1&#xff0c;因为在此系统上禁止运行脚本。 有关详细信息&#xff0c;请参阅 https:/go.microsoft.com/fwlink/?LinkID135170 中的 about_Execution_Policies。 所在…...

刷题小抄4-数组

在Python中数组的功能由列表来实现,本文主要介绍一些力扣上关于数组的题目解法 寻找数组中重复的数字 题目链接 题目大意: 给出一个数组,数组长度为n,数组里的数字在[0,n-1]范围以内,数字可以重复,寻找出数组中任意一个重复的数字,返回结果 解法一 该题最基础的思路是使用字…...

Hbase安装

目录 上传压缩包 解压 改名 修改 Hbase 配置文件 修改base-env.sh 修改hbase-site.xml 配置环境变量 修改zookeeper配置文件 复制配置文件 修改zoo.cfg配置文件 修改myid 配置环境变量 刷新配置文件 启动Hbase 进入Hbase 查看版本号 查看命名空间 查看命名空…...

面向对象设计模式:结构型模式之代理模式

一、引入 访问 FB&#xff1a;代理服务器 二、代理模式 aka Surrogate 2.1 Intent 意图 Provide a surrogate (代理) or placeholder for another object to control access to it. 为另一个对象提供一个代理或占位符&#xff0c;以控制对它的访问。代理模式给某一个对象提…...

CCF大数据专家委员会十周年纪念庆典纪实:拥抱数字时代,展望科技未来

山河远阔&#xff0c;奋进十年&#xff0c;作为国内大数据领域最权威的学术组织&#xff0c;CCF大数据专家委员会&#xff08;以下简称“大专委”&#xff09;不忘初心&#xff0c;凝心聚力&#xff0c;见证并推动了过去10年来大数据技术生态在中国的建立、发展和成熟。 2023年…...

Qt学习3-Qt Creator四则运算计算器(哔站视频学习记录)

计算器中的“”按钮这部分的代码解释 目录 制作计算器中的“”按钮这部分的代码解释 一、代码部分 二、解释 三、思路 四、死循环&#xff01; 一、代码部分 void Widget::on_equalButton_clicked() {QStack<int> s_num,s_opt; //声明两个int类型变量char opt[128…...

学习 Python 之 Pygame 开发魂斗罗(九)

学习 Python 之 Pygame 开发魂斗罗&#xff08;九&#xff09;继续编写魂斗罗1. 在子弹类中修改敌人发射子弹的位置2. 创建显示敌人子弹的函数3. 解决敌人不会向下掉落的问题4. 给敌人碰撞体组增加碰撞体5. 解决敌人叠加在一起的问题继续编写魂斗罗 在上次的博客学习 Python 之…...

最简单的SpringBoot+MyBatis多数据源实现

最简单的SpringBootMyBatis多数据源实现1.数据库准备2.环境准备3.代码部分3.1多数据源配置2.测试随着应用用户数量的增加&#xff0c;相应的并发请求的数量也会跟着不断增加&#xff0c;慢慢地&#xff0c;单个数据库已经没有办法满足频繁的数据库操作请求了&#xff0c;在某些…...

Spring Boot 3.0系列【8】核心特性篇之SpringApplication

有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot版本3.0.3 源码地址:https://gitee.com/pearl-organization/study-spring-boot3 文章目录 前言1. 启动应用2. 自定义 Banner3. 应用参数传递参数获取参数4. ApplicationRunner、CommandLineRunner5. 事件发布和监听…...

Nginx的搭建与核心配置

目录 一.Nginx是什么&#xff1f; 1.Nginx概述 2.Nginx模块与作用 3.Nginx三大作用&#xff1a;反向代理、负载均衡、动静分离 二.Nginx和Apache的差异 三.安装Nginx 1.编译安装 2.yum安装 四.Nginx的信号使用 五.Nginx的核心配置指令 1.访问状态统计配置 2.基于授…...

Java学习笔记 --- jQuery

一、jQuery介绍 jQuery&#xff0c;顾名思义&#xff0c;也就是JavaScript和查询&#xff08;Query&#xff09;&#xff0c;它就是辅助JavaScript开发的js类库。它的核心思想是write less&#xff0c;do more&#xff08;写得更少&#xff0c;做得更多&#xff09;&#xff0c…...

华为OD机试题,用 Java 解【字符串加密】问题

华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典使用说明 参加华为od机试,一定要注意不…...

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制&#xff0c;因此这个了16进制的数据既可以翻译成为这个机器码&#xff0c;也可以翻译成为这个国标码&#xff0c;所以这个时候很容易会出现这个歧义的情况&#xff1b; 因此&#xff0c;我们的这个国…...

多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验

一、多模态商品数据接口的技术架构 &#xff08;一&#xff09;多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如&#xff0c;当用户上传一张“蓝色连衣裙”的图片时&#xff0c;接口可自动提取图像中的颜色&#xff08;RGB值&…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)

在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马&#xff08;服务器方面的&#xff09;的原理&#xff0c;连接&#xff0c;以及各种木马及连接工具的分享 文件木马&#xff1a;https://w…...

STM32HAL库USART源代码解析及应用

STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)

目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 &#xff08;1&#xff09;输入单引号 &#xff08;2&#xff09;万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...

论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing

Muffin 论文 现有方法 CRADLE 和 LEMON&#xff0c;依赖模型推理阶段输出进行差分测试&#xff0c;但在训练阶段是不可行的&#xff0c;因为训练阶段直到最后才有固定输出&#xff0c;中间过程是不断变化的。API 库覆盖低&#xff0c;因为各个 API 都是在各种具体场景下使用。…...