使用lldb查看Rust不同类型的结构
目录
前言
正文
标量类型
复合类型——元组
复合类型——数组
函数
&str
struct
可变数组vec
Iter
String
Box
Rc
Arc
RefCell
Mutex
RwLock
Channel
总结
前言
笔者发现这个lldb挺好玩的,可以查看不同类型的结构,虽然这好像是C++的东西,
看看Rust的也可以,
笔者使用RustRover中的调试模式,在后面的代码,在打印语句哪一行打断点。
输出使用
expr <变量>
正文
参考如下
数据类型 - Rust 程序设计语言 中文版Rust 程序设计语言中文也译为 Rust 权威指南,是 Rust 官方推出的学习 Rust 的必备教程。Rust Wiki 版的 Rust 程序设计语言简体中文版将由 Rust 中文翻译项目组持续维护和更新,确保内容最新最全。https://www.rustwiki.org.cn/zh-CN/book/ch03-02-data-types.html
标量类型
标量(scalar)类型表示单个值。Rust 有 4 个基本的标量类型:整型、浮点型、布尔型和字符
比如
let a=1;println!("{a}")
输出
(lldb) expr a
(i32) a = 1
i32表示是32为的整数,当前值为1
获取其地址
(lldb) expr &a
(*mut i32) &a = 0x000000839274f5f4
加个引用符号。
对于其他类似的,比如u32,u8、true等,这些标量类型都是放在某一个地址中,没有其他东西。
使用其他命令——frame variable -L
(lldb) frame variable -L a0x000000d6151df964: (i32) a = 1
可以看到输出了地址、类型、变量、值。
在tauri中没有什么区别。
复合类型——元组
看看元组内部长什么样的
比如
let a=(1,2.0,'g');println!("{a:?}")
输出
(lldb) expr a
(tuple$<i32,f64,char>) a = (__0 = 1, __1 = 2, __2 = 'g')
可以使用 .0或者__0访问其中的数据
(lldb) expr a.__0
(i32) __0 = 1
(lldb) expr a.0
(i32) __0 = 1
看来这个元组是多个标量和在一起的类型
在rust代码中,无法使用 __0
类型 `(i32, f64, char)` 中没有字段 `__0` [E0609]
在tauri中没有什么区别。
复合类型——数组
let a=[1,2,3];println!("{a:?}")
输出
(lldb) expr a
([i32; 3]) a = ([0] = 1, [1] = 2, [2] = 3)
这里是i32类型,长度为3的数组。
在lldb访问其中的值,可以使用a[0],也可以使用a.0
(lldb) expr a[0]
(i32) [0] = 1
(lldb) expr a.0
(i32) [0] = 1
函数
如果是一个函数
fn f1()->i32{return 1;
}
fn main() {let a=f1;println!("123");}
a会是什么? 输出看看
(lldb) expr a
(*mut ) a = 0x0000000011117b00
*mut 表示是一个可变的指针
笔者想调用a,但是没成功
(lldb) expr a()
error: function call failed
不知道什么情况。
&str
let x="abc";println!("{x}");
换个字母。
看看&str的在lldb的输出
(lldb) expr x
(ref$<str$>) x = "abc" {data_ptr = 0x00007ff791a1a3b0length = 3
}
有两个东西,笔者都不知道改怎么称呼,就叫 字段,
有两个字段,一个data_ptr,显而易见,是存放数据的地址,可以修改
另一个length,就是长度了。
进去地址看看
(lldb) expr x.data_ptr
(*mut u8) data_ptr = 0x00007ff791a1a3b0
发现又是是个可变指针,指向一个u8类型的内存地址
可以加个*访问了
(lldb) expr *(x.data_ptr)
(u8) *data_ptr = 97
发现是97,这不就是a的ASCLL码,
访问一下其他的
(lldb) expr *x.data_ptr+1
(u32) = 98
(lldb) expr *x.data_ptr+2
(u32) = 99
没问题。
笔者本来想修改数据的,没想到失败了
(lldb) memory region x.data_ptr
[0x00007ff688860000-0x00007ff688883000) r--
memory region 是 LLDB 调试器中的一个命令,
用于显示指定内存地址所在的内存区域的属性和权限信息。
它会告诉你某个地址是否可读、可写、可执行,以及该内存区域的起始和结束范围。
可以发现,只有r,只有只读
笔者就算在变量设置mut,内存还是还是只读
但是,可以修改长度
(lldb) expr (x).length=1
(u64) length = 1
总之,这个&str就像一个“结构体”,感觉不是很准确,应该说像“json”。
笔者发现tauri 通信函数greet
#[command]
fn greet(name: &str) -> String {println!("Hello, {}!", name);format!("Hello, {}! You've been greeted from Rust!", name)
}
这个name,内存居然拥有写的权限
(ref$<str$>) name = "world" {data_ptr = 0x000001b36114b6f0length = 5
}
(lldb) memory region 0x000001b36114b6f0
[0x000001b361050000-0x000001b36114f000) rw-
笔者不能理解
struct
看看结构体
如下,
struct book<'a>{id: i32,name:&'a str,}let book1 = book{id: 1,name: "rust",};println!("{}", book1.name);
输出
(lldb) expr book1
(shared_state_concurrency::main::book) book1 = {id = 1name = "rust" {data_ptr = 0x00007ff7d53fa3b0length = 4}
}
真像json,比如取值——length
(lldb) expr book1.name.length
(u64) length = 4
没问题
可变数组vec
let a=vec![1, 2, 3];println!("{:?}", a);
输出
(lldb) expr a
(alloc::vec::Vec<i32,alloc::alloc::Global>) a = size=3 {[0] = 1[1] = 2[2] = 3
}
获取第一个字段——buf,a.0、a[0]、或者a.buf,都行
(lldb) expr a.buf
(alloc::raw_vec::RawVec<i32,alloc::alloc::Global>) buf = {inner = {ptr = {pointer = {pointer = 0x000002b284ccfc20}_marker = {}}cap = (__0 = 3)alloc = {}}_marker = {}
}
看看这个地址可不可以写
(lldb) memory region 0x000002b284ccfc20
[0x000002b284cb0000-0x000002b284cd0000) rw-
发现有w,可以写,改成66 77 88。
修改数据
memory write -s 4 0x000001d9e06a7430 42 4d 58
因为是i32类型的,32位,需要4个字节,
66是十进制,变成16进制是42
其他同理。写完后
(lldb) expr a(alloc::vec::Vec<i32,alloc::alloc::Global>) a = size=3 {[0] = 66[1] = 77[2] = 88
}
没问题
Iter
看看迭代器
let a=vec![1,2,3];let iter= a.iter();println!("{a:?}")
如果以json数据表示iter的结构,如下
{"iter": {"ptr": {"pointer": "0x000001dd45d299f0"},"end_or_len": "0x000001dd45d299fc","_marker": {}}
}
发现这个iter,pointer和 end_or_len都是地址,
意思就很明显了,从pointer开始,到end_or_len结束。
f0到fc ,中间有12个字节,类型是i32的,没问题。
String
let a=String::from("hello");println!("{:?}", a);
输出
(lldb) expr a
(alloc::string::String) a = "hello" {vec = size=5 {[0] = 104[1] = 101[2] = 108[3] = 108[4] = 111}
}
可以看到String里面放了一个vec,
(lldb) expr a.vec
(alloc::vec::Vec<u8,alloc::alloc::Global>) vec = size=5 {[0] = 104[1] = 101[2] = 108[3] = 108[4] = 111
}
这个vec元素的类型还是u8。
如果考虑成json结构,可能是这样的
{"a":{"vec": {"buf": {"inner": {"ptr": {"pointer": {"pointer": "0x000001651effdeb0"},"_marker": {}},"cap": {"__0": 5},"alloc": {}},"_marker": {}},"len": 5}}
}
没问题
Box
Box是智能指针,允许将一个值放在堆上而不是栈上
let a=Box::new(1);println!("{:?}", a);
输出,看看a长什么样
(lldb) expr a
(*mut i32) a = 0x00000279d903de90
确实是一个指针
获取其中的值*a
(lldb) memory region 0x00000279d903de90
error: 'jb_renderers_set_markup' is not a valid command.
[0x00000279d9030000-0x00000279d9050000) rw-
有写的权限
Rc
Rc被称为 引用计数
let a=Rc::new(1);println!("{:?}", a);
输出
(lldb) expr a
(alloc::rc::Rc<i32,alloc::alloc::Global>) a = strong=1, weak=0 {value = 1
}
这个Rc就比Box要复杂的得多
使用json表示内部的结构
{"a:rc":{"ptr": {"pointer":{"strong":{"value": {"value": 1}},"weak":{"value": {"value": 1}},"value":1}},"phantom":{},"alloc": {}}
}
表示的不是很准确,因为pointer其实是一个指针。
(lldb) expr a.ptr.pointer
(*mut alloc::rc::RcInner<i32>) pointer = 0x000001eb490a7710
拥有写的权限
(lldb) memory region 0x000001eb490a7710
[0x000001eb49090000-0x000001eb490b0000) rw-
使用一次clone,
let b=Rc::clone(&a);
发现strong变成了2
(lldb) expr a.ptr.pointer.strong.value.value
(u64) value = 2
Arc
Arc原子引用计数指针,可以安全地在多线程环境中共享数据
结构和Rc几乎一模一样,但是其中的类型不一样。笔者就不展示了
RefCell
允许你即使在有不可变引用时也可以改变数据
let a=RefCell::new(1);println!("{:?}", a);
输出用json表示
"a:RefCell":{"value": {"value": 1},"borrowed": {"value": {"value": 0}}}
这个RefCell 有点高级,笔者没有看到关于地址的东西
使用一下
{let mut b=a.borrow_mut();*b=2;println!("{:?}", a);}
在大括号里面,发现这个a的borrow的值
(lldb) expr a.borrow.value.value
(i64) value = -1
居然变成了-1,有点意思
Mutex
看看互斥锁
let a=Mutex::new(1);println!("{a:?}")
输出,用json表示结构
{"a:Mutex":{"inner": {"futex": {"v": {"value": 0}}},"poison": {"failed": {"v": {"value": 0}}},"data": {"value": 1}}
}
如果使用了lock
let lock=a.lock().unwrap();
可以发现futex的值变成了1
(lldb) expr a.inner.futex.v.value
(u8) value = 1
RwLock
let a=RwLock::new(1);println!("{a:?}")
其结构用json表示
{"a:RwLock": {"inner": {"state": {"v": {"value": 0}},"writer_notify": {"v": {"value": 0}}},"poison": {"failed": {"v": {"value": 0}}},"data": {"value": 1}}
}
和Mutex差不多,但是inner内部变了
很容易猜测,使用一次读锁,state对应的值变成1
使用一次写锁writer_notify对应的值变成1
但是,笔者使用读锁,确实如下
let b=a.read().unwrap();
(lldb) expr a.inner.state.v.value
(u32) value = 1
使用写锁
let mut b=a.write().unwrap();
发现并不是writer_notify变成1
(lldb) expr a
(std::sync::poison::rwlock::RwLock<i32>) a = {inner = {state = {v = (value = 1073741823)}writer_notify = {v = (value = 0)}}poison = {failed = {v = (value = 0)}}data = (value = 1)
}
而是这个state变成了一个很大的值,1073741823,这个值感觉不是巧合,笔者不能理解。
写锁是独占的。
笔者添加4个读锁,发现state对应的值变成了4
看来根据这个state的值可以判断是读锁还是写锁。具体实现笔者不是很清楚,必然和state有很大的关系。
Channel
看看通道
use std::sync::mpsc::channel;
use std::thread;
fn main() {let (tx, rx) = channel();thread::spawn(move || {let val = String::from("hi");tx.send(val).unwrap();});println!("123")
}
tx 和rx用json表示
{"tx": {"inner": {"flavor": {"0": {"counter": "0x0000020b23389b00"}}}},"rx": {"inner": {"flavor": {"0": {"counter": "0x0000020b23389b00"}}}}
}
可以发现,二者的结构是一模一样的。最后都指向一个地址。
意思就显而易见了,把某个消息传递到某个地址,然后再从这个地址中获取消息
这就是通道吗?有点意思。
总结
看了看,rust的不同类型的结构
感觉这个结构,无论是什么,好像都可以用json表示。有点意思
相关文章:

使用lldb查看Rust不同类型的结构
目录 前言 正文 标量类型 复合类型——元组 复合类型——数组 函数 &str struct 可变数组vec Iter String Box Rc Arc RefCell Mutex RwLock Channel 总结 前言 笔者发现这个lldb挺好玩的,可以查看不同类型的结构,虽然这好像是C的东…...

【Linux】线程POSIX信号量
目录 1. 整体学习思维导图 2. 信号量的概念 3. 基本接口 4. 基于环形队列的生产者消费者模型(信号量) 1. 整体学习思维导图 2. 信号量的概念 POSIX信号量和SystemV信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源目的。但 POSIX可以用于线…...
WPF中如何自定义控件
WPF自定义控件简化版:账户菜单按钮(AccountButton) 我们以**“账户菜单按钮”为例,用更清晰的架构实现一个支持标题显示、渐变背景、选中状态高亮**的自定义控件。以下是分步拆解: 一、控件核心功能 我们要做一个类似…...
大模型MCP更高效的通信:StreamableHTTP协议
随着大语言模型(LLMs)的飞速发展,模型与应用之间的通信效率和灵活性变得至关重要。Model Context Protocol (MCP) 作为专为模型交互设计的协议,一直在不断进化以满足日益增长的需求。近期,MCP引入了一个令人振奋的新特…...
防火墙在网络安全体系中的核心作用与原理
防火墙在网络安全体系中的核心作用与原理 一、核心作用解析 1. 访问控制中枢 功能维度实现方式典型场景黑白名单控制基于IP/端口/协议的规则过滤限制外部IP访问财务系统,仅开放VPN端口权限分级用户组策略映射(如AD集成)禁止普通员工访问核心…...

MySQL事务和JDBC中的事务操作
一、什么是事务 事务是数据库操作的最小逻辑单元,具有"全有或全无"的特性。以银行转账为例: 典型场景: 从A账户扣除1000元 向B账户增加1000元 这两个操作必须作为一个整体执行,要么全部成功,要么全部失败…...

每日脚本学习5.10 - XOR脚本
xor运算的简介 异或就是对于二进制的数据可以 进行同0异1 简单的演示 : 结果是 这个就是异或 异或的作用 1、比较两数是否相等 2、可以进行加密 加密就是需要key 明文 :0b010110 key : 0b1010001 这个时候就能进行加密 明文 ^ key密文 还有这个加密比…...

【编译原理】总结
核心 闭包,正则闭包 产生式(规则) 文法 G[S](,,P,S) 一组规则的集合 :非终结符 :终结符 P:产生式 S:开始符号 推导 归约 规范(最右ÿ…...

docker创建一个centOS容器安装软件(以宝塔为例)的详细步骤
备忘:后续偶尔忘记了docker虚拟机与宿主机的端口映射关系,来这里查看即可: docker run -d \ --name baota \ --privilegedtrue \ -p 8888:8888 \ -p 8880:80 \ -p 8443:443 \ -p 8820:20 \ -p 8821:21 \ -v /home/www:/www/wwwroot \ centos…...

OpenVLA:开源的视觉-语言-动作模型
1. 简介 让我们先来介绍一下什么是OpenVLA,在这里: https://openvla.github.io/ 可以看到他们的论文、数据、模型。 OpenVLA 是一个拥有 70亿参数的开源 **视觉-语言-动作(VLA)**模型。它是在 Open X-Embodiment 数据集 中的 97万…...

Matlab/Simulink的一些功能用法笔记(4)
水一篇帖子 01--MATLAB工作区的保护眼睛颜色设置 默认的工作区颜色为白色 在网上可以搜索一些保护眼睛的RGB颜色参数设置 在MATLAB中按如下设置: ①点击预设 ②点击颜色,点击背景色的三角标符号 ③点击更多颜色,找到RGB选项 ④填写颜色参数…...
【比赛真题解析】混合可乐
这次给大家分享一道比赛题:混合可乐。 洛谷链接:U561549 混合可乐 【题目描述】 Jimmy 最近沉迷于可乐中无法自拔。 为了调配出他心目中最完美的可乐,Jimmy买来了三瓶不同品牌的可乐,然后立马喝掉了一些(他实在是忍不住了),所以 第一瓶可口可乐最大容量为 a 升,剩余 …...

Elasticsearch:我们如何在全球范围内实现支付基础设施的现代化?
作者:来自 Elastic Kelly Manrique SWIFT 和 Elastic 如何应对基础设施复杂性、误报问题以及日益增长的合规要求。 金融服务公司在全球范围内管理实时支付方面面临前所未有的挑战。SWIFT(Society for Worldwide Interbank Financial Telecommunication -…...

matlab介绍while函数
MATLAB 中的 while 语句介绍 在 MATLAB 中,while 语句是一种循环结构,用于在满足特定条件时反复执行一段代码块。与 for 循环不同,while 循环的执行次数是动态的,取决于循环条件是否为真。 语法 while condition% 循环体代码 e…...

如何解决 PowerShell 显示 “此系统上禁用了脚本运行” 的问题
在 Windows 11 或 10 的 PowerShell 中运行脚本时,你可能会遇到一个错误,提示系统上禁用了脚本运行。这是一种安全功能,而不是系统问题,旨在防止可能有害的脚本自动运行。然而,如果你需要运行脚本来完成某些任务,或者你在系统上做了软件开发或测试的环境,那么你需要在 P…...

深入浅出之STL源码分析4_类模版
1.引言 我在上面的文章中讲解了vector的基本操作,然后提出了几个问题。 STL之vector基本操作-CSDN博客 1.刚才我提到了我的编译器版本是g 11.4.0,而我们要讲解的是STL(标准模板库),那么二者之间的关系是什么&#x…...
探索科技的前沿动态:科技爱好者周刊
探索科技的前沿动态:科技爱好者周刊 在信息爆炸的时代,我们每时每刻都被新技术、新理念包围。而如何在这纷繁复杂的信息中找到对自己有价值的内容,成了一大挑战。今天,我们要介绍的是一个宝贵的资源——科技爱好者周刊,它致力于为科技爱好者提供优质的科技资讯,每周五发…...

初学者入门指南:什么是网络拓扑结构?
初学者入门指南:什么是网络拓扑结构? 在构建或学习计算机网络时,一个绕不开的核心概念便是“网络拓扑结构”(Network Topology)。它决定了网络中各个设备如何连接、通信以及如何扩展。理解网络拓扑不仅有助于我们更清…...
在 Vue 3 中实现刮刮乐抽奖
🎉 在 Vue 3 中实现刮刮乐抽奖 当项目中需要做一些活动互动页时,需要实现刮刮乐,请看如下效果: 这里感谢github用户Choicc分享的组件,具体可点击传送门查看 1. 引入组件 将/src/components下ScratchCard.vue复制到自…...

Satori:元动作 + 内建搜索机制,让大模型实现超级推理能力
Satori:元动作 内建搜索机制,让大模型实现超级推理能力 论文大纲一、背景:LLM 推理增强的三类方法1. 基于大规模监督微调(SFT)的推理增强2. 借助外部机制在推理时进行搜索 (RLHF / 多模型 / 工具)3. 现有局限性总结 二…...

SDC命令详解:使用all_outputs命令进行查询
相关阅读 SDC命令详解https://blog.csdn.net/weixin_45791458/category_12931432.html all_outputs命令用于创建一个输出端口对象集合,关于设计对象和集合的更详细介绍,可以参考下面的博客。 Synopsys:设计对象https://chenzhang.blog.csdn…...

printf调试时候正常,运行时打印不出来
问题是在添加了 printf 功能后,程序独立运行时无法正常打印输出,而调试模式下正常。这表明问题可能与 printf 的重定向实现、标准库配置、或编译器相关设置有关。 解决: 原来是使用 Keil/IAR,printf可能需要启用 MicroLIB 或正确…...

解决 TimeoutError: [WinError 10060] 在 FramePack项目中连接 Hugging Face 超时的问题
#工作记录 以下是针对 TimeoutError: [WinError 10060] 的完整排查方案,适用于 FramePack项目中。 (一般该错误的发生原因请重点排查Hugging Face模型仓库受限需要登录的情形) FramePack项目参考资料 FramePack部署(从PyCharm解…...

分布式-Redis分布式锁
Redis实现分布式锁优点 (1)Redis有很高的性能; (2)Redis命令对此支持较好,实现起来比较方便 实现思路 (1)获取锁的时候,使用setnx加锁,并使用expire命令为锁…...

UniRepLknet助力YOLOv8:高效特征提取与目标检测性能优化
文章目录 一、引言二、UniRepLknet 的框架原理(一)架构概述(二)架构优势 三、UniRepLknet 在 YOLOv8 中的集成(一)集成方法(二)代码实例 四、实验与对比(一)对…...

自研时序大模型讲解(4月29日)直播回顾
4 月 29 日,清华团队揭秘:时序大模型如何让数据“活”起来线上直播圆满结束。清华大学软件学院博士生,IoTDB 原生机器学习引擎 AINode 研发同学刘雍在线上面向数千人次的时序数据分析人员与 AI 大模型行业关注者,就时序大模型的发…...
The Action Replay Process
Preface A commonly used inequality − x > ln ( 1 − x ) , 0 < x < 1 -x > \ln(1 - x), \quad 0 < x < 1 −x>ln(1−x),0<x<1 Proof: Let f ( x ) ln ( 1 − x ) x f(x) \ln(1 - x) x f(x)ln(1−x)x, for 0 < x < 1 0 < …...

k8s之ingress解释以及k8s创建业务的流程定义
matchLabels ingress Ingress 是反向代理规则,用来规定 HTTP/S 请求应该被转发到哪个 Service 上,比如根据请求中不同的 Host 和 url 路径让请求落到不同的 Service 上。 Ingress Controller 就是一个反向代理程序,它负责解析 Ingress 的反向…...
LVGL对象的盒子模型和样式
文章目录 🧱 LVGL 对象盒子模型结构🔍 组成部分说明🎮 示例代码📌 总结一句话 🧱 一、样式的本质:lv_style_t 对象🎨 二、样式应用的方式🧩 三、样式属性分类(核心&#…...

从0开始学习大模型--Day05--理解prompt工程
提示词工程原理 N-gram:通过统计,计算N个词共同出现的概率,从而预测下一个词是什么。 深度学习模型:有多层神经网络组成,可以自动从数据中学习特征,让模型通过不断地自我学习不断成长,直到模型…...