如何使用gdb查看堆栈情况?怎么查看?bt 或 info stack 有什么区别?

Linux——gdb调试器 Linux的gdb调试器的使用方法,及其指令介绍 阅读详情
AI摘要

本文详细解释了GDB中的bt(backtrace)和infostack命令在查看函数调用堆栈和详细信息方面的差异,通过实例展示了如何在GDB中使用这些命令来调试程序,特别关注了在Redis服务器中的应用。,

bt 和 info stack 有什么区别?

bt 和 info stack 是 GDB(GNU Debugger)中的两个不同命令,用于查看调试信息的不同方面:

  1. bt(backtrace)命令:

    • bt 命令用于获取当前线程的函数调用堆栈信息。
    • 它会显示当前线程中函数调用的序列,从当前位置回溯到程序的入口点。
    • 这有助于我们查看程序执行的路径,以找到问题所在。
  2. info stack 命令:

    • info stack 命令用于显示当前线程的调用堆栈的更详细信息,包括局部变量和寄存器值。
    • 它提供了比 bt 更详细的堆栈信息,包括局部变量、函数参数以及堆栈帧的更多细节。

下面就是bt的使用示例

在 GDB 中,我们可以使用 backtrace 或 bt 命令来查看当前线程的函数调用堆栈,也可以使用 info stack 命令查看。

首先在终端中启动 GDB,并将需要调试的程序作为参数传入。

$ gdb my_program

设置断点或者直接运行程序。当程序暂停时,可以使用 bt 或 backtrace 命令来查看堆栈情况。

(gdb) bt
#0  my_function (arg1=42, arg2=1337) at my_file.c:123
#1  0x00005555555552b5 in main () at main.c:12

上面的输出结果包括了当前线程的每个函数调用以及它们所在的文件、行号和参数值等信息。其中第一行是最近一次调用的函数,而最后一行是整个堆栈的起始位置(即 main 函数)。

如果想要查看某个特定帧(frame)的详细信息,可以使用 frame 或者简写为 f 命令加上帧编号进行切换。

(gdb) f 0    // 切换到第一个帧
#0  my_function (arg1=42, arg2=1337) at my_file.c:123
123     return arg1 + arg2;
   
(gdb) f 1    // 切换到第二个帧
#1  0x00005555555552b5 in main () at main.c:12
12      int result = my_function(42, 1337);

除了 bt 命令,还可以使用 info stack 命令来查看当前线程的堆栈信息。


info stack 命令通常用于在调试器中查看当前线程的堆栈信息,我们一般按照以下步骤来查看当前线程的堆栈信息:

  1. 启动 GDB 并加载可执行文件或核心转储文件。
  2. 在 GDB 中暂停程序执行,可以使用 Ctrl+C 来中断正在运行的程序。
  3. 使用 info threads 命令来查看所有线程的列表。这将列出所有正在运行的线程,并显示它们的标识符(通常是线程 ID)。
  4. 选择要查看堆栈信息的特定线程,可以使用 thread [thread_id] 命令,其中 [thread_id] 是想要查看的线程的标识符。例如,thread 1 选择线程 ID 为 1 的线程。
以下是一个info statck的示例会话:
$ gdb my_program
(gdb) run
[Program is running...]
^C
(gdb) info threads
  1 Thread 0x7ffff7fc1a40 (LWP 15931)  0x00007ffff7bc8723 in poll () from /lib/x86_64-linux-gnu/libc.so.6
* 2 Thread 0x7ffff776e700 (LWP 15935)  main () at my_program.c:10
(gdb) thread 2
[Switching to thread 2 (Thread 0x7ffff776e700 (LWP 15935))]
(gdb) info stack
#0  main () at my_program.c:10

在这个示例中,我们先使用 info threads 命令列出了所有线程,然后选择了线程 ID 为 2 的线程,最后使用 info stack 查看了这个线程的堆栈信息。堆栈信息中列出了函数调用的序列,以及每个函数的位置。

最后再来个真实示例,以 make 后的 Redis 为例:

(gdb) gdb redis-server
(gdb) r
 ... 此处输出信息很多,省略
 # 按 Ctrl+C 
 ^C
(gdb) info threads
  Id   Target Id                                            Frame
* 1    Thread 0x7ffff7c53680 (LWP 876498) "redis-server"    0x00007ffff7d7346e in epoll_wait (epfd=5, events=0x7ffff78fd000, maxevents=10128, timeout=100) at ../sysdeps/unix/sysv/linux/epoll_wait.c:30
  2    Thread 0x7ffff7119700 (LWP 876502) "bio_close_file"  futex_wait_cancelable (private=<optimized out>, expected=0, futex_word=0x5555558c22c8 <bio_newjob_cond.lto_priv+40>) at ../sysdeps/nptl/futex-internal.h:183
  3    Thread 0x7ffff6918700 (LWP 876504) "bio_aof"         futex_wait_cancelable (private=<optimized out>, expected=0, futex_word=0x5555558c22f8 <bio_newjob_cond.lto_priv+88>) at ../sysdeps/nptl/futex-internal.h:183
  4    Thread 0x7ffff6117700 (LWP 876505) "bio_lazy_free"   futex_wait_cancelable (private=<optimized out>, expected=0, futex_word=0x5555558c2328 <bio_newjob_cond.lto_priv+136>) at ../sysdeps/nptl/futex-internal.h:183
  5    Thread 0x7ffff5916700 (LWP 876506) "jemalloc_bg_thd" futex_wait_cancelable (private=<optimized out>, expected=0, futex_word=0x7ffff7a168b0) at ../sysdeps/nptl/futex-internal.h:183
(gdb) thread 2
[Switching to thread 2 (Thread 0x7ffff7119700 (LWP 876502))]
#0  futex_wait_cancelable (private=<optimized out>, expected=0, futex_word=0x5555558c22c8 <bio_newjob_cond.lto_priv+40>) at ../sysdeps/nptl/futex-internal.h:183
183	../sysdeps/nptl/futex-internal.h: No such file or directory.
(gdb) info stack
#0  futex_wait_cancelable (private=<optimized out>, expected=0, futex_word=0x5555558c22c8 <bio_newjob_cond.lto_priv+40>) at ../sysdeps/nptl/futex-internal.h:183
#1  __pthread_cond_wait_common (abstime=0x0, clockid=0, mutex=0x5555558c2380 <bio_mutex.lto_priv>, cond=0x5555558c22a0 <bio_newjob_cond.lto_priv>) at pthread_cond_wait.c:508
#2  __pthread_cond_wait (cond=cond@entry=0x5555558c22a0 <bio_newjob_cond.lto_priv>, mutex=mutex@entry=0x5555558c2380 <bio_mutex.lto_priv>) at pthread_cond_wait.c:647
#3  0x000055555566d1e8 in bioProcessBackgroundJobs (arg=0x0) at bio.c:233
#4  0x00007ffff7e4e609 in start_thread (arg=<optimized out>) at pthread_create.c:477
#5  0x00007ffff7d73133 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95

OK,动动小手开始实践吧。( 😊 别忘了点赞、收藏。感谢~)

C++堆栈空间分配与指针使用实战指南 内存管理是C++开发的核心基础,其中堆(heap)和栈(stack)的空间分配机制直接影响程序性能与稳定性。栈空间由编译器自动管理,采用LIFO原则,适合存储局部变量和函数参数;堆空间则需手动管理,适合大块数据或长生命周期对象。指针作为内存访问的关键工具,在堆栈分配中扮演重要角色——栈指针由硬件支持,堆指针则通过地址变量维护。理解这些机制对避免内存泄漏、栈溢出等常见问题至关重要,尤其在嵌入式系统和性能敏感场景中。现代C++通过智能指针、移动语义等技术优化内存管理,而内存池等模式能有效减少碎片。掌握堆栈分配原 阅读详情

相关推荐

Linux下C语言真实执行机制:编译、内存、调试全链路解析

C语言在Linux中并非孤立语法,而是深度耦合于GCC编译流程、内核内存管理(MMU/brk/mmap)和GDB调试机制的系统级实践。其执行本质是源码经预处理→编译→汇编→链接四阶段生成ELF文件,再由内核按虚拟内存布局加载;malloc等标准库调用最终映射为sbrk或mmap系统调用,而GDB通过ptrace与/proc/pid/maps协同实现内存观测。理解这一‘Linux+C’双轨模型,是解决Segmentation fault、valgrind内存泄漏、GDB断点失效等高频问题的技术根基,也是嵌入式

weixin_34301132的博客 447

GDB常用指令

GDB:run,执行程序:next,下一步,不进入函数:step,下一步,会进入函数:breakponit,设置断点:list,查看源码:continue,继续执行到下一断点:backtrace,查看当前调用栈:print,打印查看变量:quit,退出 GDB:查看对象类型:查看所有的断点:查看局部变量:查看函数的参数值及要返回的变量值:堆栈帧信息:查看 goroutines 信息。在使用前 ,需要注意先执行 source /usr/local/go/src/runtime/runtime-gdb.py:查

神棍之路 3050

从二进制到Flag:x64 ELF逆向工程实战与CTF解题全流程解析

逆向工程是理解程序内部逻辑、分析软件行为的关键技术,广泛应用于安全研究、漏洞分析和CTF竞赛。其核心原理在于通过静态与动态分析相结合的方法,将机器码还原为可理解的逻辑。这项技术的价值在于能够深入剖析软件工作机制,发现潜在漏洞或验证程序安全性。在应用场景上,它不仅是安全研究人员的必备技能,也是开发者进行代码审计和性能分析的有效手段。本文聚焦于x64架构的ELF可执行文件,详细阐述了从初始信息收集、使用IDA Pro进行静态反汇编,到利用GDB进行动态调试跟踪的完整实战路径。通过结合具体案例,文章深入探讨了如何

weixin_33778544的博客 291

gdb调试

在实际使用 GDB 调试时,还可以利用条件断点,即在设置断点时添加条件,只有满足条件时才会中断程序执行。可以使用 condition <断点编号> <条件表达式> 为断点设置条件,只有当条件表达式为真时,程序才会在断点处暂停。2. 查看调用栈信息:使用 bt 命令,从下往上查看站点调用情况,需先编译带有符号的二进制文件。• 示例:delete <断点编号> ,根据 info b 显示的断点编号删除指定断点。• u 表示单元大小,如 b (字节)、h (半字,2 字节)、w (字,4 字节)等。

weixin_51430302的博客 1282

内存越界读取排查实战:从崩溃日志到根因定位

内存越界读取是C/C++开发中最隐蔽的崩溃来源之一:它不像越界写入那样立刻破坏数据,而是可能默默读取“脏数据”,在数周甚至数月后才以随机崩溃、花屏或计算错误的形式暴露。要理解这类问题,需要从进程的访问违规信号(如SIGSEGV、SIGBUS)入手,再借助core dump还原崩溃现场。在工程实践中,Valgrind和AddressSanitizer是两款互补的检测利器,前者适合小规模数据验证,后者能在编译期插桩直接输出越界位置。在音视频处理、网络协议栈、游戏客户端、嵌入式系统等场景中,缓冲区边界计算错误、函

weixin_34293141的博客 373

常用gdb调试命令

step s 执行下一条语句,若该语句为函数调用,则进入函数内的第一条语句。next n 执行下一条语句,不会进入函数内部执行。thread apply all bt 打印所有线程的调用栈。info threads 查看当前进程的所有线程。set var name=v 设置变量的值。bt 10 打印tid=10的线程调用栈。t 10 切换到tid=10的线程。info reg 查看当前的寄存器值。

大罗山下瓯江畔的博客 701

GDB 使用指南

debug 神器

lyndon 601

如何快速查看进程/子线程堆栈

如何快速查看进程/子进程堆栈

木简熙的博客 6254

CANN oam-tools asys 工具 coredump 文件解析实战指南:从 core 文件到 stackcore 堆栈

CANN oam-tools 是昇腾场景下的故障定位工具集,其 asys 组件提供了故障信息收集、软硬件信息展示、AI Core error 报错分析等能力。本文聚焦 asys 的 `analyze -r=coredump` 解析能力:当进程在执行任务过程中因 Segmentation fault 等信号异常退出并生成 core 文件时,如何利用该功能将 core 文件解析为 stackcore

gitblog_00696的博客 558

DaVinci Configurator实战:从DBC导入到通信栈配置全解析

本文详细解析了如何使用Vector DaVinci Configurator工具,从导入行业标准DBC文件开始,高效完成AutoSAR通信栈(包括COM、PduR、CanIf等模块)的自动化与精细化配置。文章通过实战步骤,重点阐述了DBC导入、与EB MCAL协同、核心模块参数调整及诊断标定服务集成等关键环节,旨在帮助汽车电子工程师快速掌握这一核心工具,提升开发效率与准确性。

weixin_29159127的博客 592

Android Profiler 帧率优化实战与性能调优

本文详细介绍了使用Android Profiler进行帧率优化与性能调优的实战方法。通过分析主线程状态、FPS曲线和渲染阶段耗时,精准定位卡顿根源,并提供减少过度绘制、优化绘制命令及改善资源使用的具体策略。文章结合电商、游戏等真实案例,帮助开发者有效解决卡顿问题,提升应用流畅度。

palm99的专栏 536

编译与调试完全指南—第5章 GDB调试详解

文章摘要 《GDB调试详解》全面介绍Linux下强大的源代码级调试器GDB。文章从启动与连接、程序执行控制、断点设置、数据查看、堆栈分析到多线程/多进程调试等核心功能展开,采用"启动连接→执行控制→断点观察→数据操作→堆栈分析→高级调试→实战场景"的知识体系结构。重点讲解了本地调试、进程附加、交叉调试(使用gdbserver)和Coredump事后分析四种调试场景,并详细说明了GDB启动参数、配置文件.gdbinit的使用方法以及常见调试技巧。该指南是进行嵌入式开发、系统编程和问题定位的重要参考资源。

weixin_43149888的博客 221

ESP32-S3双屏AI吊坠:微型边缘智能终端设计实践

边缘智能终端是指在设备端完成数据感知、处理与响应的嵌入式系统,其核心在于低延迟、高隐私与弱网适应性。基于ESP32-S3等轻量级主控,通过语音唤醒、本地AI推理与双屏异步渲染等关键技术,可构建资源受限场景下的实用化人机交互节点。这类设计显著降低对云端依赖,提升实时性与数据安全性,广泛应用于智能穿戴、IoT交互面板及便携式语音设备。本文以‘璀璨·AI吊坠’为实例,深入解析双面圆形屏驱动、ES8311音频链路优化、VAD+Porcupine本地语音流水线,以及亚微安级低功耗状态机实现,为微型AI终端的软硬协同开

weixin_42348783的博客 634

GDB调试进阶:掌握变量、寄存器与执行流控制的核心技巧

在软件开发和系统调试领域,调试器是定位和修复程序缺陷的核心工具。其工作原理是通过控制程序执行流程、监控内存状态和寄存器变化,实现对程序运行时的深度观察。从技术价值看,熟练使用调试器不仅能快速定位问题,更能帮助开发者深入理解程序在硬件层面的实际执行过程,提升对计算机系统工作原理的认知。在嵌入式开发、系统编程和性能优化等应用场景中,调试器的底层操作能力尤为关键。本文聚焦于GDB调试器的进阶功能,详细解析如何通过`info convenience`命令管理调试会话中的临时变量,以及利用`info register

376

JavaSpringBoot + VUE 相关开发环境配置合集

1.Java环境-JDK安装 参照:Java基础1-环境篇:JDK安装与环境变量配置 Java基础1-环境篇:JDK安装与环境变量配置_第一段代码的博客-优快云博客_jdk 2.Web服务器-Tomcat安装 原创Java服务器Tomcat安装和配置 3.Maven(后面为了项目兼容性,使用了3.0.5版本) 原创Maven安装和配置(Maven3.0.5) 4.nginx 原创nginx轻量级Web服务器安装和配置 5 数据库mysql 原创数据库Mysql安装和配置 ...

第一段代码的博客 3164

YOLOv12改进策略【Neck】| arXiv 2024 MAFPN:多分支辅助特征金字塔网络 | 通过双向辅助融合与异构卷积机制,解决传统PAFPN多尺度特征融合不充分与小目标检测不足问题

本文记录的是利用MAFPN颈部结构改进YOLOv12的目标检测网络模型。通过引入双向辅助融合机制优化特征处理流程,在自底向上路径利用 SAF 模块融合主干浅层特征与颈部输出,并保留浅层空间信息,为小目标检测提供更丰富细节;自顶向下路径通过 AAF 模块建立密集连接,聚合浅层高 / 低分辨率层、同级层及前层特征,均衡各层通道数后实现多向梯度信息交互,增强中 / 大目标特征表达。将其应用到中,解决传统特征金字塔在多尺度信息整合中的不足,提升多尺度目标检测的精度与特征表达的丰富性。Multi-Branch Aux

Limiiiing的博客 1256

GDB汇编调试实战:从黑盒崩溃到指令级精准定位

在软件开发和系统调试中,理解程序在CPU层面的实际执行过程是深入排查复杂问题的关键。通过反汇编技术,开发者可以将高级语言代码映射到底层机器指令,直观观察寄存器、内存和指令指针的实时状态,从而掌握程序运行的底层原理。这项技术的核心价值在于能够穿透编译器优化和符号表缺失的障碍,精准定位那些高级调试器难以触及的深层缺陷,例如栈溢出、内存越界和多线程竞态条件。在Linux开发环境中,GDB调试器内置了强大的反汇编引擎和指令级控制能力,为分析系统调用、库函数实现以及无符号表程序提供了不可替代的手段。通过结合热门的GD

weixin_33866037的博客 312

12-RK平台U-Boot启动流程

先看概述,把这一章要回答的问题摆出来,带着问题听。RK 特有的 BootROM -> MiniLoader -> SPL -> U-Boot -> Kernel。这是因为 RK 平台使用闭源的 DDR 初始化固件,需要通过 MiniLoader 来加载和运行。为什么多一层?这是 RK 平台的特殊性决定的。RK 平台使用闭源的 DDR 初始化固件,这段代码 Rockchip 不开源,只能以二进制形式提供,它需要一个载体来加载和运行,这个载体就是 MiniLoader。

内核笔记 1147

GDB逆向工程实战:从漏洞定位到ROP利用链构造

在软件安全与逆向工程领域,调试器是理解程序运行时行为、分析漏洞原理的核心工具。GNU调试器(GDB)作为一款功能强大的底层调试工具,其价值在于提供了对进程内存、寄存器、执行流的完全控制能力,使安全研究员能够动态地观察和干预程序执行。这种能力对于分析缓冲区溢出、释放后重用等内存破坏漏洞至关重要,尤其是在面对缺乏源码和符号信息的二进制程序时。通过结合静态分析,GDB的动态调试功能允许研究人员验证假设、跟踪数据流,并精准定位漏洞触发点。在实战中,这直接应用于漏洞利用链的构造,例如通过计算偏移、控制指令指针(EIP

weixin_30616969的博客 319

【数据集实例】CMIP6气候模式数据下载-以河东地区为例

以河东地区为例,介绍CMIP6数据下载及处理

WW、forever的博客 4945

BUCK-BOOST升降压电路Multisim电路仿真分析

本文分析了三极管型BUCK-BOOST升降压开关电源的工作原理。该电路结合了BUCK降压和BOOST升压拓扑,通过控制三极管Q1的高频通断,使电感L1周期性储能和释能,实现输出电压可高于或低于输入电压且极性相反。详细阐述了Q1导通和关断阶段的工作过程,推导了输出电压与占空比的关系式Vo=-D/(1-D)*Vi,并分析了不同占空比下的工作模式(降压、升压)。通过Multisim仿真验证了理论分析,当D=25%时输出降压至1.6V,D=60%时输出升压至7.5V。电路具有升降压灵活、极性反转、效率高等特点,适用

XU157303764的博客 1436

嵌入式内存管理面试高频考点:堆栈、内存对齐与大小端实战解析

在嵌入式软件开发中,内存管理是决定系统稳定性的基石,也是技术面试中高频考察的核心能力。从底层原理来看,堆与栈的分配机制、结构体因内存对齐产生的隐藏填充、以及多字节数据在大小端模式下的存储差异,共同构成了C语言与硬件交互的底层逻辑。理解这些概念不仅能解释为什么结构体sizeof结果常与直观计算不符,更能帮助开发者规避栈溢出、非对齐访问和协议解析错乱等工程隐患。在单片机裸机或RTOS环境中,合理设置任务栈大小、利用哨兵值检测栈水位、按对齐规则优化结构体布局,都是提升代码质量与RAM利用率的关键实践。同时,在通信

weixin_34327761的博客 435

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Linux C开发硬核指南:从内存管理到GCC/GDB底层原理

C语言在Linux环境下的实际运行,远不止语法层面——它深度依赖ELF加载机制、glibc内存分配器(ptmalloc)、GCC链接与优化行为,以及内核的虚拟内存管理(mmap/brk、页表权限)。理解`char *p = "hello"`为何不可修改,本质是`.rodata`节的`PROT_READ`映射与MMU写保护协同的结果;而`malloc(0)`返回非NULL却解引用崩溃,则揭示了用户态内存管理器与内核页映射之间的契约边界。这些机制共同构成Linux C程序的底层执行基础,直接影响内存安全、调试可

weixin_33919950的博客 396

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

libunwind 堆栈回溯实战指南:崩溃现场如何把一串地址还原成完整调用链

当程序崩溃时,你通常只能得到类似 `0x7f8c2a1b3e40` 这样的十六进制地址,而 libunwind 正是那个能把堆栈回溯(stack unwinding)变成清晰函数调用链的 C 库。本文从一个真实的线上事故讲起,带你搞懂它的工作原理、搭建方法、常用 API 和常见坑,最终能独立写出一套属于自己的崩溃现场回溯工具。 ## 凌晨三点,线上服务崩了,可栈上只有一串十六进制地址 先讲个我

gitblog_00971的博客 889

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Linux C开发必备:GCC编译选项与GDB调试实战指南

C语言开发中,编译与调试是绕不开的两大核心环节。GCC作为最常用的编译工具链,其告警选项与调试信息生成直接影响问题排查效率;而GDB调试器则能帮助开发者深入程序内部,在运行时精准定位崩溃原因。理解编译优化与调试符号的平衡,掌握条件断点、远程调试及脚本化调试等进阶技巧,能大幅提升故障排查能力。本文从编译选项到调试实战,系统梳理了Linux环境下C程序开发的关键工具用法,结合真实踩坑案例,帮助开发者建立高效的调试思维,从‘盲写碰运气’走向‘精准定位’。

weixin_34301132的博客 321

嵌入式Linux Qt应用卡死问题深度排查:从线程阻塞到死锁的实战解析

在嵌入式Linux开发中,Qt应用程序的界面卡死、进程假死是工程师最常遇到的棘手问题之一。这类问题往往涉及主线程阻塞、多线程死锁、设备节点读写异常等复杂根因,单靠代码审查难以快速定位。本文从卡死现象的本质分类出发,系统讲解如何通过gdb attach、core dump、线程堆栈分析等手段捕捉现场,并结合串口同步读取、跨线程信号槽、底层驱动阻塞等高频案例,剖析问题产生的原理与工程修复方案。掌握这些排查思路,不仅能提升嵌入式Qt应用的稳定性,也能在实战中快速缩小故障范围。通过合理的线程模型、超时机制和锁序规范

weixin_33805743的博客 439
上一篇: Mac/m1终端配置自动登录ssh服务器等后续操作
下一篇: 什么是领域驱动设计(DDD): 领域驱动设计和实践如何做
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天河书阁 VicRestart

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值