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

C++-Rust-一次性掌握两门语言

C++-Rust-一次性掌握两门语言

  • 简介
  • 特色
  • 数据类型
  • 声明常量、变量
  • 判断与循环
  • 函数
  • 抽象化的对象:类与接口
  • 枚举
  • 模板与泛型
  • Lambda匿名函数表达式

简介

本文主要是通过介绍C++和Rust的基础语法达成极速入门两门开发语言。
C++是在C语言的基础之上添加了面向对象的类、重载、模板等特性和大量标准库以达到让使用者更高效地进行开发工作,其适用场景主要是游戏应用、游戏引擎、数据库等底层架构开发(而C更适合于系统内核、云搜索等算法和内存管理要求极高的程序)。
Rust则是吸取了Typescript、Python、C++、Go等各类前辈的语法特色创建出来的现代化语言,最重要的特点就是所有权与借用的特性,使之让很多内存问题在编译阶段甚至在编写代码时就能实时告知开发者,避免了众多运行时问题。

特色

C++最大的特点就是使用指针*和引用&来自由地操作内存地址与值,但开发者使用不当也很容易造成内存泄漏。

void main() {//  直接在栈上创建实例,好处是随着作用域结束而自动销毁,无需手动管理User user;//  在堆上创建实例并拿到指针,好处是将随着程序一直存在,当不使用后需要手动进行销毁User *user = new User();//  手动销毁,否则若程序一日未结束,则该内存块一直被占据delete user;    
}

Rust最大的特点是所有权与借用的概念,Rust中大部分变量要不通过引用来指向同个地址,要不是直接移动而非复杂变量,通过严格控制来减少内存泄漏的可能性。

fn main() {///  直接在栈上创建实例let mut user = User {};///  将执行移动,使user变得不可用let user2 = user;///  提供一个只读引用指向user2相同的内存块,两者都可用,但user3只是可读,不可写let user3 = &user2;///  提供一个可写引用指向user2相同的内存块,这会让user2暂时失效,直到user4的作用域结束,同一时间只能存在一个可写引用let mut user4 = &mut user2;/// 不允许存在另一个可写引用// let mut user5 = &mut user2;
}

可以简单地理解为Rust做的各种赋值操作背后都是采用C++的std::move()函数将右值放入左值,或者将左值移动到左值,而C++自身如果不使用std::move()函数的话,赋值几乎都是直接复制(浅拷贝/深拷贝)一个新的,这样在释放内存时可能因为多次释放导致空悬指针,进而报错。

Rust还有另一特点是没有Null值,而是使用枚举Option::Some/None来指代结果可能为空的情况,类似于C++的std::optional可选值,Rust大量使用Option和基于此的Result来指定参数与返回值的可选性。

以下函数展示一个第二个值可能为空,根据情况进行运算并返回结果:

use std::error::Error;fn plus_val(value: i32, plus: Option<i32>) -> Result<i32, Error> {match plus { Option::Some(v) => {if v == 1 {return Error("plus can't be 1.")}value * v},Option::None => value * 2,}
}fn test() {let result1 = plus_val(2, Option::None);    // 2 * 2 = 4let result2 = plus_val(2, Option::Some(4)); //  2 * 4 = 8//  可以用match语法搭配枚举值处理match result1 {Ok(r1) => println!("{}", r1),Err(error) => panic!("r1 error!")}//  也可以直接链式处理(此处只处理成功情况)result2.and_then(|r2| println!("{}", r2));
}

数据类型

两者的数据类型相差不多,甚至可以说大部分开发语言的数据类型都是这些。

类型\语言C++Rust说明
布尔型boolbool可取值只有true和false,用于指代一些状态开关
有符号短整型short inti32Rust使用字母i加上比特位数来表示有符号的整数类型,整型变量的默认类型
更短的有符号整型i8,i16
有符号整型inti64C++最常使用的整型变量类型
有符号长整型long inti128
无符号整型unsigned intu64
无符号短整型unsigned short intu32
无符号长整型unsigned long intu128
更短的无符号整型u8, u16
字符charchar注意C++的字符是12个字节,而Rust的字符是14个字节,占据更大空间也意味着嫩表示更广的字符集或者更多字符
字符串(不可变)const char*&strC++的不可变是通过指定一个常量字符指针指向字面量所在地址,而Rust的定义类似,是定义一个引用指向字面量地址,只不过依旧可以修改引用指向的地址,即重新赋值
字符串std::stringString可变字符串,可随时对内部字符进行增删改,注意Rust的String实际是对vec的封装
空值voidunit表示没有值、空值、无值的情况,常用于函数的返回值
定长数组int[4] 或者 std::array<int,4>[i32;4]用于存放固定数量的相同类型值,这里都定义了固定数量4,类型为整型。由于长度在编译期就能确定,意味着可以预先分配好
元组std::tuple<T1,T2,…,Tn>(T1,T2,…,Tn)用于存放若干个不同类型但相同用途的值,类似于数组版的结构体

其他比较常用的内置类型:

  • 可变长度数组:C++为std::vector,Rust为vec,这是这类开发语言中更常用的数组类型,可变长度意味着更适用于实际场景根据输入进行长度变动。
  • 哈希表:C++为std::unorder_map<KeyType, ValueType>,Rust为HashMap<KeyType, ValueType>,大部分算法或者要求唯一键名的用途都会大量使用哈希表。

声明常量、变量

C++属于传统的强类型编程语言,由于认为类型是必须在编译前就定好(静态类型),因此类型都是先于变量名、函数名之前指定的,如声明一个变量并给其赋予初始值:

// 声明常量,需要在类型前面加上const关键字,类型为int
const int num1 = 1;
// 声明变量,类型为int
int num2 = 1;

Rust吸收了现代语言的特性,虽然依旧认为类型是必须的,但也尽可能通过自动推断减少开发者多余的类型定义工作:

fn variable() {
// 声明常量,使用let关键字,此处自动推断类型为i32let num1 = 1;
// 声明变量,在let关键字后添加mut关键字,此处自动推断类型为i32let mut num2 = 1;
}

以上声明等同于let num1: i32 = 1;let mut num2: i32 = 1;

判断与循环

C++使用传统的if、else、switch作为判断,使用for、while作为循环:

void handler(std::vector<unsigned int>& list) {unsigned int max = 0;for (auto *it = list.begin(); p != list.end(); p++) {unsigned int temp = *it;switch (temp) {case 1:temp = 2;break;case 3:temp = 4;break;default:break;}if (temp > max)max = temp;}
}

Rust除了有if、else、while、for之外,将switch换成了match减少了多余的语法,还有永久循环loop,并且都可以直接获取到返回值:

fn handler(list: &[u32]) {let max = 0;for &item in list {//  注意temp可以直接拿到返回值let temp = match item { 1 => 2,3 => 4,_ => item};max = if temp > max { temp } else { max };}
}

函数

C++定义函数是返回值类型在前,函数名称在后:

void main() {// 函数体
}

Rust遵从现代语言方式,用关键字表示这是一个函数声明,并将类型放在后面:

fn main() -> unit {// 函数体
}

抽象化的对象:类与接口

C++拥有struct结构体和class类,但没有interface接口,且这两者实际上除了一个默认声明为public公开,一个为private隐藏之外,并无其他区别。
C++一般是在.h头文件中声明结构体和类作为抽象化的用途。

头文件中定义结构体和类声明:

struct User {std::string name;bool enable;unsigned int level;
};
//  定义接口
struct IUserController {
private:User* user;
public:virtual void init();virtual User& getInfo();
};

cpp文件中实现类方法和使用结构体:

// 实现接口,在类里如果没有说明,默认都是隐藏
class UserController: public IUserController {User* user;
public:void init() override {delete user;user = new User{ "Way",true, 1 };}User& getInfo() override {return *user;};
}

cpp文件中使用类:

void main() {UserController uCtrler;uCtrler.init();std::cout << uCtrler.getInfo() << std::endl;
}

Rust中虽然有结构体,但并没有类,结构体是同时作为结构体和类来使用的,同时提供了trait特征作为类似接口的存在提供各种抽象化。由于没有头文件的概念,需要自己分隔声明、实现、调用的文件结构。

定义结构体和类声明:

// 声明结构体
struct User {name: String,enable: bool,level: u64,
}//  定义接口pub trait GetInfo {fn get_info() -> &User;
}//  声明类
struct UserController {user: User,
}//  实现接口
impl GetInfo for UserController {fn get_info(&self) -> &User {&self.user}
}// 定义类方法
impl UserController {fn init_user_info(&mut self) {self.user = User { name: String::from("Way"), enable: true, level: 1 };}
}

使用类:

fn main() {let u_ctrler = UserController { user: User { name: "Way", enable: true, level: 1 } };u_ctrler.init();println!("{}", u_ctrler.getInfo());
}

要注意特征和接口有不一样的地方,就是特征只能定义方法,不能定义属性/状态,即变量,是因为Rust更期望做好内存管理,如果这么定义那每个实现特征时都有大量额外内存开辟,不符合Rust对内存的严格管理。
而C++更自由地让开发者直接操作内存,主要也和C++的接口实际是通过抽象类与头文件声明来间接实现的,只要开发者知道自己在做什么C++就允许。

枚举

两者差别不大,不过C++的枚举是忽略枚举名称的,使用时是直接使用属性名:

enum PlayerStatus {PLAYER_MOVE,PLAYER_STOP
}void check_status(PlayerStatus status) {std::cout << status == PLAYER_MOVE << std::endl;
}

Rust除了遵循枚举名::属性名的使用方式之外,还允许在内部继续定义结构体,类似Kotlin的密封类,这样可以让枚举完成更多更复杂的功能,方便封装状态操作等。

enum PlayerStatus {MOVE,STOP,OTHER {name: String,value: i8}
}impl PlayerStatus::OTHER {fn equal(&self, &value: i8) -> bool {self.value == value}
}fn check_status(status: PlayerStatus) {println!("{}", status == PlayerStatus::MOVE);
}

模板与泛型

C++中只有一种类似于泛型但更加强大的特性:template模板,其不仅可以装填类型,还能附加常量值,使之能用于创建多个不同版本的类或函数。

以下例子使用模板创建一个包含长度为7的整形数组的类,并传递名称:

template<T, Size>
class TheTemplate {T *arr[Size];std::string name;
public:TheTemplate(std::string *_name, T *_arr[Size]): name(*_name), arr(_arr) {};
}void create() {TheTemplate week<int, 7>{"星期", new int[7]{1,2,3,4,5,6,7}};TheTemplate month<int, 12>{"月份", new int[7]{1,2,3,4,5,6,7,8,9,10,11,12}};
}

注意该类是在编译期就根据已确定的模板创建多个副本类,抹除模板的存在,类似这样:

class TheTemplate1 {int *arr[7];std::string name;
public:TheTemplate1(std::string *_name, int *_arr[7]): name(*_name), arr(_arr) {};
}class TheTemplate2 {int *arr[12];std::string name;
public:TheTemplate1(std::string *_name, int *_arr[12]): name(*_name), arr(_arr) {};
}void create() {TheTemplate1 week{"星期"};TheTemplate2 month{"月份"};
}

而Rust中泛型除了用于装载类型外,还能用于装载生命周期注解,并广泛用于创建不同类型的类与函数。
生命周期注解是Rust特有的具象化生命周期概念,其用单引号加小写字母的形式表示如’a,'b。生命周期注解并不会直接改变变量、参数、返回值本身的生命周期,而是类似类型一样对其本身的生命周期进行要求和约束。
以下同样是创建一个与上述例子相同的泛型结构体,并使用生命周期’a来约束入参与返回值应该具有的生命周期:

struct TheGenerator<T> {arr: [T],name: String,
}impl<T> TheGenerator<T> {fn getWelcome<'a>(&self, word: &'a str) -> &'a String {self.name + word}
}fn create() {//  注意这里的泛型也可以不用填写,Rust可以根据初始值自动推断let week = TheGenerator::<i8> {arr: [1, 2, 3, 4, 5, 6, 7],name: "星期",};let month = TheGenerator {arr: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],name: "月份",};//  符合规则时不需要显示传递生命周期注解let result = month.getWelcome("hello");println!("{}", result);
}

以上的getWelcome方法中约束了出参的生命周期必须达到与入参一样长,要注意出参的生命周期并没有被缩短,还是按照原本的规则(这里的规则是出参使用了结构体的name属性,因此出参与结构体实例化后的生命周期一致,直到

Rust的泛型也是和C++的模板一样会在编译期就生成多个结构体副本,抹除泛型的存在。
Rust还有一个简化版的泛型约束,先看看原本约束方式:

fn SeeMe<T: Add>(a: T, b: &T) -> T {a + b
}fn useMe() {SeeMe(1, 2);
}

以上实现了对函数参数类型约束,要求两个参数都为T类型并且实现了Add相加的特征,也可以简写为以下方式:

fn SeeMe(a: impl Add) -> impl Add {a + 1
}fn useMe() {SeeMe(2);
}

要求泛型同时具有多种类型,除了直接使用加号<T: Add + Copy>的方式外,还可以使用where从句:

use std::fmt::Display;fn some_fn<T, U>(a: &T, b: &U) -> i32 where T: Add + Copy, U: Add + Display + PartialEq {if a > b {println!("{}", *b);}a + b
}

Lambda匿名函数表达式

C++版,采用,类型可以使用std::function<ParamType,ReturnType>或者直接用auto表示:

void lambda(int value) {auto func = [](int)=>{ std::cout << x << std::endl; };func(value);
}

Rust版,采用竖线开始并用于分隔参数列表和函数体:

fn lambda(value: &i32) {let func = |x: &i32| println!("fn!{}", x);func(value)
}

相关文章:

C++-Rust-一次性掌握两门语言

C-Rust-一次性掌握两门语言 简介特色数据类型声明常量、变量判断与循环函数抽象化的对象&#xff1a;类与接口枚举模板与泛型Lambda匿名函数表达式 简介 本文主要是通过介绍C和Rust的基础语法达成极速入门两门开发语言。 C是在C语言的基础之上添加了面向对象的类、重载、模板等…...

汇编调用C语言定义的全局变量

在threadx移植中&#xff0c;系统的systick通过了宏定义的方式定义&#xff0c;很难对接库函数的时钟频率&#xff0c;不太利于进行维护 所以在C文件中自己定义了一个systick_Div的变量&#xff0c;通过宏定义方式设定systick的时钟频率 在汇编下要加载这个systick分频系数 …...

WEB 文件包含 /伪协议

首先谈谈什么是文件包含 WEB入门——文件包含漏洞与PHP伪协议_文件包含php伪协议_HasntStartIsOver的博客-CSDN博客 文件包含 程序员在编写的时候 可能写了自己的 函数 如果想多次调用 那么就需要 重新写在源代码中 太过于麻烦了只需要写入 funcation.php然后在需要引用的地…...

ComPDFKit PDF SDK库(支持Windows、Web、Android、iOS、Mac等平台)

ComPDFKit提供专业、全平台支持的PDF开发库&#xff0c;包括Windows、Mac、Linux、Android、iOS、Web平台。开发者可以快速、灵活整合PDF功能到各开发平台的软件、程序、系统中。丰富的功能&#xff0c;多种开发语言&#xff0c;灵活的部署方案可供选择&#xff0c;满足您对PDF…...

微服务契约测试框架-Pact

契约测试 契约测试的思想就是将原本的 Consumer 与 Provider 间同步的集成测试&#xff0c;通过契约进行解耦&#xff0c;变成 Consumer 与 Provider 端两个各自独立的、异步的单元测试。 契约测试的优点&#xff1a; 契约测试与单元测试以及其它测试之间没有重复&#xff0c…...

LightGlue论文翻译

LightGlue:光速下的局部特征匹配 摘要 - 我们介绍 LightGlue&#xff0c;一个深度神经网络&#xff0c;学习匹配图像中的局部特征。我们重新审视 SuperGlue 的多重设计决策&#xff0c;稀疏匹配的最新技术&#xff0c;并得出简单而有效的改进。累积起来&#xff0c;它们使 Lig…...

iOS开发-CAShapeLayer与UIBezierPath实现微信首页的下拉菜单效果

iOS开发-CAShapeLayer与UIBezierPath实现微信首页的下拉菜单效果 之前开发中遇到需要使用实现微信首页的下拉菜单效果。用到了CAShapeLayer与UIBezierPath绘制菜单外框。 一、效果图 二、CAShapeLayer与UIBezierPath 2.1、CAShapeLayer是什么&#xff1f; CAShapeLayer继承自…...

《Elasticsearch 源码解析与优化实战》第5章:选主流程

《Elasticsearch 源码解析与优化实战》第5章&#xff1a;选主流程 - 墨天轮 一、简介 Discovery 模块负责发现集群中的节点&#xff0c;以及选择主节点。ES 支持多种不同 Discovery 类型选择&#xff0c;内置的实现称为Zen Discovery ,其他的包括公有云平台亚马逊的EC2、谷歌…...

Spring Cloud Alibaba - Nacos源码分析(三)

目录 一、Nacos客户端服务订阅的事件机制 1、监听事件的注册 2、ServiceInfo处理 serviceInfoHolder.processServiceInfo 一、Nacos客户端服务订阅的事件机制 Nacos客户端订阅的核心流程&#xff1a;Nacos客户端通过一个定时任务&#xff0c;每6秒从注册中心获取实例列表&…...

DOCKER镜像和容器

1.前言 ​ 初见DOCKER&#xff0c;感觉和我们常用的虚拟机&#xff08;VMware&#xff0c;viurebox&#xff09;类似&#xff0c;是一个独立于宿主机的模块&#xff0c;可以解决程序在各个系统间的移植&#xff0c;但它真的仅仅是这样嘛&#xff1f; 2.容器的优缺点 1.1.容器…...

探索网页原型设计:构建出色的用户体验

在当今数字化时代&#xff0c;用户对网页体验的要求日益提高。在网页设计过程中&#xff0c;扮演着至关重要的角色。通过网页原型设计&#xff0c;产品经理能够更好地展示和传达网页的整体布局、导航结构、元素位置和交互效果&#xff0c;从而使团队成员更清晰地了解设计意图&a…...

48,排序算法merge

功能描述&#xff1a; 两个容器元素合并&#xff0c;并储存到另一容器中 函数原型&#xff1a; merge(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest); //容器元素合并&#xff0c;并存储到另一个容器中 //注意&#xff1a;两个容器必须是有序的…...

【MySQL】复合查询

复合查询目录 一、基本查询二、多表查询三、自连接四、子查询4.1 单行子查询4.2 多行子查询4.3 多列子查询4.4 在from子句中使用子查询4.5 合并查询4.5.1 union4.5.2 union all 五、实战OJ 一、基本查询 --查询工资高于500或岗位为MANAGER的雇员&#xff0c;同时还要满足他们的…...

JavaScript中的this指向及绑定规则

在JavaScript中&#xff0c;this是一个特殊的关键字&#xff0c;用于表示函数执行的上下文对象&#xff0c;也就是当前函数被调用时所在的对象。由于JavaScript的函数调用方式多种多样&#xff0c;this的指向也因此而变化。本文将介绍JavaScript中this的指向及绑定规则&#xf…...

css中预编译理解,它们之间区别

css预编译&#xff1f; css预编译器用一种专门的编程语言&#xff0c;它可以对web页面样式然后再编译成正常css文件&#xff0c;可以更加方便和高效的编写css代表。主要作用就是为css提供了变量&#xff0c;函数&#xff0c;嵌套&#xff0c;继承&#xff0c;混合等功能&#…...

如何使用Java处理JSON数据?

在Java中&#xff0c;您可以使用许多库来处理JSON数据。以下是使用一种常见的库 Gson 的示例&#xff1a; 首先&#xff0c;确保您已经将 Gson 库添加到您的项目中。您可以在 Maven 中添加以下依赖项&#xff1a; <dependency><groupId>com.google.code.gson<…...

java设计模式-观察者模式

什么是观察者模式 观察者模式&#xff08;Observer&#xff09;是软件设计中的一种行为模式。 它定义了对象之间的一对多关系&#xff0c;其中如果一个对象改变了状态&#xff0c;所有依赖它的对象都会自动被通知并更新。 这种模式包含了两种主要的角色&#xff0c;即被观察…...

HiveSQL SparkSQL中常用知识点记录

目录 0. 相关文章链接 1. hive中多表full join主键重复问题 2. Hive中选出最新一个分区中新增和变化的数据 3. Hive中使用sort_array函数解决collet_list列表排序混乱问题 4. SQL中对小数位数很多的数值转换成文本的时候不使用科学计数法 5. HiveSQL & SparkSQL中炸裂…...

mac不识别移动硬盘导致无法拷贝资源

背景 硬盘插入到Mac电脑上之后&#xff0c;mac不识别移动硬盘导致无法拷贝资源。 移动硬盘在Mac上无法被识别的原因可能有很多&#xff0c;多数情况下&#xff0c;是硬盘的格式与Mac电脑不兼容。 文件系统格式不兼容 macOS使用的文件系统是HFS或APFS&#xff0c;如果移动硬盘是…...

Opencv的Mat内容学习

来源&#xff1a;Opencv的Mat内容小记 - 知乎 (zhihu.com) 1.Mat是一种图像容器&#xff0c;是二维向量。 灰度图的Mat一般存放<uchar>类型 RGB彩色图像一般存放<Vec3b>类型。 (1)单通道灰度图数据存放样式&#xff1a; (2)RGB三通道彩色图存放形式不同&#x…...

CTF show Web 红包题第六弹

提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框&#xff0c;很难让人不联想到SQL注入&#xff0c;但提示都说了不是SQL注入&#xff0c;所以就不往这方面想了 ​ 先查看一下网页源码&#xff0c;发现一段JavaScript代码&#xff0c;有一个关键类ctfs…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

高频面试之3Zookeeper

高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个&#xff1f;3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制&#xff08;过半机制&#xff0…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

2.Vue编写一个app

1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...

【网络安全】开源系统getshell漏洞挖掘

审计过程&#xff1a; 在入口文件admin/index.php中&#xff1a; 用户可以通过m,c,a等参数控制加载的文件和方法&#xff0c;在app/system/entrance.php中存在重点代码&#xff1a; 当M_TYPE system并且M_MODULE include时&#xff0c;会设置常量PATH_OWN_FILE为PATH_APP.M_T…...