Lua 5.1.1 源代码阅读笔记:

Lua-5.3.0源代码阅读(1) Lua-5.3.0源代码阅读(1) 记录代码下载,阅读工具,阅读的顺序,以及编译源代码的过程。 阅读详情
 
Lua 5.1.1 源代码阅读笔记:
(推荐在Notepad++中打开并开启C语言模式)
   
去年的《程序员》上半年部分除了第二期之外,其他的都不怎么样;但是今年的却不一样,特别是算法与开源手册这两章,真实极务实的。这一期中,发现 了Lua 这块圭玉,十分欣喜。下载把玩两天后,感觉语法不怎么样,有点混,不清晰,除此之外,定位什么的都相当精彩!昨天读了读 "The implementation of Lua 5.0",感触挺多的,今天决定看看源代码,试炼一下。
一段一段的说吧,先是数据表示的数据结构:(Lua.h 72~82)
#define LUA_TNONE  (-1)
#define LUA_TNIL  0
#define LUA_TBOOLEAN  1
#define LUA_TLIGHTUSERDATA 2
#define LUA_TNUMBER  3
#define LUA_TSTRING  4
#define LUA_TTABLE  5
#define LUA_TFUNCTION  6
#define LUA_TUSERDATA  7
#define LUA_TTHREAD  8
以上是Lua的八种结构(虽然上面不止八种):
① Nil(nil空类型,类似于Scheme的‘(),Python的None),
② Boolean(布尔值),
③ Number(数字是C中的Double,和PASCAL中的Real,只在一些特殊的机型上才会被替换为Integer),④String(字符串不是C的ASCIZ,是类PASCAL型),
⑤ Table(就是一个Table,但是可以用任意的类型(除nil)来索引任意的类型,5.0后使用了侯捷先生所谓的无痛哲学,包装了Table和Array)
⑥ Function(当然是函数了,即所谓的First-Class,广泛用于Scheme,ML中,相当的方便)
⑦ UserData(自定义的用户数据结构,有Light和Heavy两种,后者由Lua来分配管理,用GC)
⑧ Thread(线程,CoRoutine)
怎么样,上面几个#define就明白了吧?(Lua的作者们似乎受PASCAL的影响很深,从T前缀可见;另外从命名法可以看出)
接着:(lua.h 120~126)
LUA_API int   (lua_gettop) (lua_State *L);
LUA_API void  (lua_settop) (lua_State *L, int idx);
LUA_API void  (lua_pushvalue) (lua_State *L, int idx);
…………
LUA_API int   (lua_checkstack) (lua_State *L, int sz);
显然,这是基本的Stack的操作,别的不说,我们看看lua_State,这是什么呢?(Lstate.h 100~126)
struct lua_State {
  CommonHeader;
  lu_byte status;
  StkId top;  /* first free slot in the stack */
  StkId base;  /* base of current function */
  …………
  TValue l_gt;  /* table of globals */
  TValue env;  /* temporary place for environments */
  GCObject *openupval;  /* list of open upvalues in this stack */
  GCObject *gclist;
  struct lua_longjmp *errorJmp;  /* current error recover point */
  ptrdiff_t errfunc;  /* current error handling function (stack index) */
};
观察一下,应该是虚拟机的Stack部分。当中省略了一部分。在"The implementation of Lua 5.0"中有这么一段关于Lua的数据表示:
typedef struct {
 int t;
 Value v;
} TObject;
和
typedef union {
 GCObject *gc;
 void *p;
 lua_Number n;
 int b;
} Value;
这是Lua的数据表示,既然用了union那么自然,C在这个方面的类型检查并不是非常的严厉,所以一切的数据都可以装得下,且只用一个统一的指 针就好了,不用void *转换。诚然这样极为浪费存储器空间,但是,大家仔细想想,Lua的用途是什么?Lua可以用来配置C/C++程序,这就是它的 定位。数学计算,sorry,it's not my business.
继续,对于一个指向内存特定区域的GCObject是什么样的呢?(Lstate.h 135~144)
union GCObject {
  GCheader gch;
  union TString ts;
  union Udata u;
  union Closure cl;
  struct Table h;
  struct Proto p;
  struct UpVal uv;
  struct lua_State th;  /* thread */
};
名字都很清晰,代码真是没的说,对于仅仅需要地址的TString,Udata和Closure用union,对于Table,Proto,UpVal,thread自然需要更多的信息。看看TString:(Lobject.h 199~207)
作者: 125.33.54.*
 
2006-11-8 16:48   回复此发言  

2 Lua 5.1.1 源代码阅读笔记
typedef union TString {
  L_Umaxalign dummy;  /* ensures maximum alignment for strings */
  struct {
    CommonHeader;
    lu_byte reserved;
    unsigned int hash;
    size_t len;
  } tsv;
} TString;
其中L_Umaxalign是
typedef LUAI_USER_ALIGNMENT_T L_Umaxalign ;
而LUAI_USER_ALIGNMENT_T是
#define LUAI_USER_ALIGNMENT_T union { double u; void *s; long l; }
明白了吗?这里是一个对齐(Alignment),对齐double,void*和long。为什么要写这三个?不是double最长吗?根据不 同的机器,不同的编译器的定义是不同的。因此同时用这三者来代表最长的数和最长的指针。这一点可以从注释中看出来,同样,为什么叫“USER”呢,因为这 因机器而定,需要USER们来修改。
TString中的dummy自然就是占位符咯。
看看Udata:(Lobject.h 215~223)
typedef union Udata {
  L_Umaxalign dummy;  /* ensures maximum alignment for `local' udata */
  struct {
    CommonHeader;
    struct Table *metatable;
    struct Table *env;
    size_t len;
  } uv;
} Udata;
Udata这种用户类型也是由Table来完成的,但是从这里暂时还看不出来Udata怎么区分Light和Heavy的。
该代码下放的Proto部分有个TValue其原型:(Lobject.h 73~75)
typedef struct lua_TValue {
  TValuefields;
} TValue;
而TValuefields:(Lobject.h 71)
#define TValuefields Value value; int tt
这就是所谓的TObject二元组(value,tag)。
对于频频出现的CommonHeader,有:(Lobject.h 43)
#define CommonHeader GCObject *next; lu_byte tt; lu_byte marked
有一个问题目前还是不清楚,即dummy要做最大的对齐,但是uv和tsv明显比dummy占用的字节要多,那么怎么对齐呢?
在展示两端赋值语句:(Lobject.h 138~141)
#define setthvalue(L,obj,x) /
 { TValue *i_o=(obj); /
  i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTHREAD; /
  checkliveness(G(L),i_o); }
以及:(Lobject.h 119~120)
#define setnvalue(obj,x) /
  { TValue *i_o=(obj); i_o->value.n=(x); i_o->tt=LUA_TNUMBER; }
逻辑很清晰,由特定的宏函数来赋值。同样,我们看看Light和Heavy的Udata:
#define setpvalue(obj,x) /
  { TValue *i_o=(obj); i_o->value.p=(x); i_o->tt=LUA_TLIGHTUSERDATA; }
和
#define setuvalue(L,obj,x) /
  { TValue *i_o=(obj); /
    i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUSERDATA; /
    checkliveness(G(L),i_o); }
向用一个i_o指针指向l-value。
这里,笔者对(x)的结构不太熟悉,因而追踪setuvalue(L,obj,x)的caller:(Lapi.c 1018~1027)
LUA_API void *lua_newuserdata (lua_State *L, size_t size) {
  Udata *u;
  lua_lock(L);
  luaC_checkGC(L);
  u = luaS_newudata(L, size, getcurrenv(L));
  setuvalue(L, L->top, u);      //注:在这里
  api_incr_top(L);
  lua_unlock(L);
  return u + 1;
}
接着回头看lua_State,那个栈类型:(Lstate.h 103)
StkId top;  /* first free slot in the stack */
接着是StkId:(Lobject.h 193)
typedef TValue *StkId;  /* index to stack elements */
原来就是一个指向TValue的指针呀。cast的定义是:(Llimits.h 75)
#define cast(t, exp) ((t)(exp))
接着是checkliveness:(LObject.h 111~113)
#define checkliveness(g,obj) /
  lua_assert(!iscollectable(obj) || /
  ((ttype(obj) == (obj)->value.gc->gch.tt) && !isdead(g, (obj)->value.gc)))
其中iscollectable:(LObject.h 189)
#define iscollectable(o) (ttype(o) >= LUA_TSTRING)
还有isdead:(Lgc.h 70)
#define isdead(g,v) ((v)->gch.marked & otherwhite(g) & WHITEBITS)
另外还有GCheader:(Lobject.h 49~51)
typedef struct GCheader {
  CommonHeader;
} GCheader;
总体说来,这些结构都不难,但是组织得很好。解释一下吧:
setXvalue()中的X是类型的代称。对于非GC类型,直接设置其Value的值及tt的值;对于GC类型,要用cast将该L- Value转换成 GCObject *,接着设置tt,再检查是否活跃checkliveness(G(L),i_o)。checkliveness中 再断言iscollectable,其 gc的gcheader的tt是否与这个obj的类型一样,再者isdead。其中的iscollectable 用的方法是观察obj的tt是否大于 LUA_TSTRING,因为在那之后的都是可以收集的。 
Lua源码分析(1) Lua源码分析(1) -- 简介收藏 新一篇: Lua源码分析(2) -- 对象表示 | 旧一篇: Ruby 在 VC Express 2005 下的编译 function StorePage(){d=document;t=d.selection?(d.selection.type!=None?d.selection.createRange().text:):(d. 阅读详情

相关推荐

Lua源代码阅读(一)

lualib.h   打开Lua api库函数    Lua5.3中❤️增utf8库 #define LUA_UTF8LIBNAME "utf8" LUAMOD_API int (luaopen_utf8) (lua_State *L); jks

TTc 's share 2238

如何安装lua5.1版本

然后检查一下是否安装成功,执行lua -v即可。

weixin_34542632的博客 826

lua 5.3语法分析的BNF

看lua解释器源代码的时候发现和lua官网上给的有点出入,自己记录一下 官网的文档:https://www.lua.org/manual/5.3/manual.html,直接在页面搜索BNF就行了 以下是从源码的注释里扣出来的: block -> statlist statlist -> { stat [';'] } fieldsel -> ['.' | ':'] NAM...

Monster_ixx的博客 1189

Lua 5.1参考手册

Lua 5.1参考手册 1 - 介绍 Lua是一种扩展编程语言,旨在支持具有数据描述功能的通用程序编程。它还为面向对象编程,函数式编程和数据驱动编程提供了很好的支持。Lua旨在用作任何需要的程序的功能强大,轻量级的脚本语言。Lua被实现为一个库,用干净的 C语言编写(即,在ANSI C和C ++的公共子集中)。 作为一种扩展语言,Lua没有“主要”程序的概念:它只能嵌入主机客户端

xinqingwuji的博客 2229

Lua 5.1中文编程手册:全面指南与实践

本文还有配套的精品资源,点击获取 简介:Lua是一种轻量级脚本语言,常嵌入到应用程序中提供扩展性。本手册是Lua 5.1版本的官方文档中文翻译,涵盖了语法、特性到使用方法的全面指南。内容包括基础语法、数据类型、表、控制结构、函数、模块、元编程、错误处理、C接口、垃圾收集、线程及标准库等关键概念。此外,还包含如何解压和使用手册的说明。手册适用于各级别开发者,并为多个应用领域提...

weixin_35414484的博客 2722

Lua 5.1源代码分析与设计实践

Lua语言诞生于1993年,由巴西里约热内卢天主教大学的Roberto Ierusalimschy、Waldemar Celes和Luiz Henrique de Figueiredo三位科学家设计,作为嵌入式脚本语言存在,因其轻量级、高效率的特点迅速获得了广泛的关注和应用。Lua虚拟机是Lua语言的核心组件,它将Lua的抽象语法树(AST)转换成可执行的字节码,并执行这些字节码。虚拟机的设计理念强调简洁、高效和可移植性,这使得Lua成为嵌入式编程的理想选择。

weixin_34547628的博客 997

跟着 Lua 5.1 官方参考文档学习 Lua (11)

Lua 标准库- 字符串、数组

alenliu's blog 1559

C++开发的LUA脚本解释器源代码

LUA是一种轻量级的脚本语言,最初由巴西里约热内卢天主教大学于1993年开发。设计之初,其目标是作为嵌入式语言,提供一种简单、高效的方式来扩展应用程序的功能。经过多年的演化,LUA已成为游戏开发和嵌入式系统中常用的脚本语言之一。

weixin_42499004的博客 945

推荐开源项目:Lua 5.1 - 动态编程语言的轻量级解决方案

推荐开源项目:Lua 5.1 - 动态编程语言的轻量级解决方案 1、项目介绍 Lua 5.1 是一个强大的轻量级脚本语言,专为扩展应用程序而设计。它不仅在软件开发中发挥着重要作用,也被广泛用作通用的独立编程语言。作为一个免费软件,Lua 可以在学术和商业领域自由使用,并且在全球范围内有无数的成功应用案例。 2、项目技术分析 Lua 的核心特性在于其简洁的语法和高效的执行效率。它是纯 ANSI C ...

gitblog_00079的博客 429

LUA5.1 脚本语言 编译执行源码

993 年在巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro in Brazil)诞生了一门编程语言,发明者是该校的三位研究人员,他们给这门语言取了个浪漫的名字——Lua,在葡萄牙语里代表美丽的月亮。事实证明她没有糟蹋这个优美的单词,Lua语言正如它名字所预示的那样成长为一门简洁、优雅且富有乐趣的语言。 Lua从一开始就是作为一门方便嵌入(其它应用程序)并可扩展的轻量级脚本语言来设计的,因此她一直遵从着简单、小巧、可移植、快速的原则,官方实现完全采用ANSI C编写,能以C程序库的形式嵌入到宿主程序中。Lua的每个版本都保持着开放源码的传统,不过各版采用的许可协议并不相同,自5.0版(最新版是5.1) 开始她采用的是著名的MIT许可协议。正由于上述特点,所以Lua在游戏开发、机器人控制、分布式应用、图像处理、生物信息学等各种各样的领域中得到了越来越广泛的应用。其中尤以游戏开发为最,许多著名的游戏,比如Escape from Monkey Island、World of Warcraft、大话西游,都采用了Lua来配合引擎完成数据描述、配置管理和逻辑控制等任务。 作为一门过程型动态语言,Lua有着如下的特性:1、变量名没有类型,值才有类型,变量名在运行时可与任何类型的值绑定;2、语言只提供唯一一种数据结构,称为表(table),它类似key-value关联数组,可以用任何类型的值作为key和value。提供了一致且富有表达力的表构造语法,使得Lua很适合描述复杂的数据;3、函数是一等类型,支持匿名函数和正则尾递归(proper tail recursion);4、支持词法定界(lexical scoping)和闭包(closure);5、提供thread类型和结构化的协程(coroutine)机制,在此基础上可方便实现协作式多任务;6、运行期能编译字符串形式的程序文本并载入虚拟机执行;7、通过元表(metatable)和元方法(metamethod)提供动态元机制(dynamic meta-mechanism),从而允许程序运行时根据需要改变或扩充语法设施的内定语义;8、能方便地利用表和动态元机制实现基于原型(prototype-based)的面向对象模型;9、从5.1版开始提供了完善的模块机制,从而更好地支持开发大型的应用程序; Lua 的语法类似PASCAL和Modula但更加简洁,所有的语法产生式规则(EBNF)不过才60几个。熟悉C和ASCAL的程序员一般只需半个小时便可将其完全掌握。而在语义上Lua则与Scheme极为相似,她们完全共享上述的1、3、4、6点特性,Scheme的continuation与协程也基本相同只是自由度更高。最引人注目的是,两种语言都只提供唯一一种数据结构:Lua的表和Scheme的列表(list)。正因为如此,有人甚至称Lua为“只用表的Scheme”。

lua5.1版本源代码

学习Lua源码,是掌握lua应用开发的关键。下面是截取网络关于lua使用介绍,仅供参考: Lua 是一个小巧的脚本语言。作者是巴西人。该语言的设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。 Lua脚本可以很容易的被C/C++代码调用,也可以反过来调用C/C++的函数,这使得Lua在应用程序中可以被广泛应用。不仅仅作为扩展脚本,也可以作为普通的配置文件,代替XML,Ini等文件格式,并且更容易理解和维护。 Lua由标准C编写而成,代码简洁优美,几乎在所有操作系统和平台上都可以编译,运行。 一个完整的Lua解释器不过200k,在目前所有脚本引擎中,Lua的速度是最快的。这一切都决定了Lua是作为嵌入式脚本的最佳选择。

lua源代码分析01:lua源代码结构分析

“标题1”第三方

魏波 7595

深入解析以太网接口中的BOB Smith电路设计

本文深入解析以太网接口中的BOB Smith电路设计,详细介绍了其在共模噪声抑制、浪涌防护和EMI优化中的关键作用。通过实际案例和设计要点,帮助工程师正确选择75Ω电阻和高压电容等元件,优化PCB布局,解决电压型与电流型PHY的设计差异,以及千兆与百兆以太网的特殊考量。

weixin_28339967的博客 688

读书笔记《Lua设计与实现》 了解Lua底层

  孙广东  2017.10.8 http://blog.csdn.NET/u010019717   十一抽时间看了这本书。           还记得第一次接触Lua 是在2014年7月份, 当时还是在长春实习(Cocos Lua), 接触了一个多月就来北京开始了Unity   我是很喜欢看纸质书的,不太喜欢看电子书。 作者说这是第一本揭示Lua实现原理的图书。   这个历史就不...

游戏路上的小学生 1万+

Python遥感图像处理指南(2)-卫星影像分析MNDWI提取

在第一篇文章中,我们使用了我们导入的软件包中已定义的函数,如 rasterio 中的 open 和 read 以及 matplotlib 中的 imshow。现在,我们可以编写自己的函数了。函数是一段代码,它接收一些参数作为输入并返回输出(经过一些计算),可以在代码中多次重复使用,也可以被其他代码重用。在 Python 中定义一个新函数非常简单。return v在此语法示例中,arg1和arg2强制参数,应该传递给函数,否则会引发错误,而arg3是一个可选参数,如果是,则假定默认值 1从函数调用中省略。

gis收藏家的博客 1576

论文阅读------Exposure Fusion: A Simple and Practical Alternative to High Dynamic Range Photography

Mertens T, Kautz J, Van Reeth F. Exposure fusion: A simple and practical alternative to high dynamic range photography[C]//Computer graphics forum. Oxford, UK: Blackwell Publishing Ltd, 2009, 28(1): 161-171. 摘要 本文提出了一种将包围曝光的序列融合到高质量图像中的技术,而无需先转换为高动态范围(HD.

qq_25283239的博客 3397

如何轻松反编译Lua 5.1代码?luadec51反编译工具完整使用指南

你是否曾经需要查看Lua字节码背后的源代码?luadec51是一款专为Lua 5.1版本打造的强大反编译工具,能够帮助开发者将编译后的Lua字节码转换回易读的源代码。本文将带你全面了解这个实用工具的安装、配置和使用方法,让Lua反编译工作变得简单高效。 ## ???? 工具简介:什么是luadec51? luadec51是一个专注于Lua 5.1版本的反编译工具,它可以将Lua字节码文件(.lua...

gitblog_00257的博客 940

区块链入门:用账本、乐高和三台旧电脑讲懂分布式账本

区块链是一种去中心化的分布式账本技术,其核心原理是通过密码学哈希、共识机制和链式结构实现数据不可篡改与多方共同验证。它不依赖单一中心,而是将交易记录同步复制到多个节点,依靠数学规则而非人工信任达成一致,从而在数字世界构建可验证的信用基础设施。这种‘集体见证’模式显著提升了系统抗单点故障与人为干预的能力,广泛应用于供应链溯源、数字身份、教育管理及公益透明等需强信任保障的场景。本文以账本类比、乐高拆解和Ganache实操为线索,面向零基础读者通俗解析哈希值、挖矿与智能合约等关键概念。

weixin_30517215的博客 276

Lua 源代码阅读指南

Online Lua 5.1 source code browser Recommended reading order: lmathlib.c, lstrlib.c: get familiar with the external C API. Don't bother with the pattern matcher though. Just the easy functions

useryecha的专栏 652

C2f-DCN模块详解:可变形卷积与特征融合的完美结合

C2f模块作为YOLOv8的核心创新,代表了目标检测特征提取模块设计的最新进展。通过精简的卷积配置(仅2个基础卷积)、高效的特征重用设计(部分通道分割复用)、以及深层语义与浅层细节的协同建模能力,C2f在结构设计和性能表现上全面超越了前代的C3模块。与C3K2、C3K等变体相比,C2f在遮挡和密集环境下的检测鲁棒性更优,而C3K2和C3K分别在高速检测和多尺度检测方面有专门优化。这种差异化设计反映了YOLO系列模型向场景化、专业化发展的趋势。从设计原理角度看,C2f的核心优势在于其多路径梯度流动优化和。

浩瀚之水的专栏 379

Multisim14.0仿真应用设计(十六)74LS138译码器应用仿真

74LS138为3线-8线译码器。

zhusl6688的博客 2982

Lua5.1代码阅读(七):lvm.h/lvm.c

  Lua5.1代码阅读(七):lvm.h/lvm.c   (未完成,待修改) 一、概览 lvm.h/lvm.c的作用是提供底层的Lua虚拟机。 这个模块主要是用于循环读取并分解指令, 然后根据其操作码的枚举值进行处理或跳转到Lua的其它模块。 内部的函数引用图如下:   参考资料: * A No-Frills Introduction to Lua...

weimingtom的待宵草 1504

【数字IC验证进阶】正则表达式(Regular Expression)快速入门指南

在芯片开发过程中,正则表达式的使用非常常见。初次上手晦涩难懂,多用几次爱不释手!

悟已往之不谏 知来者之可追 1441

【免费下载】 推荐开源项目:unluac - LUA 5.x 反编译器

在编程世界中,有时候我们需要对已编译的代码进行逆向工程,以理解其内部工作原理或优化代码。对于LUA这种轻量级脚本语言,[unluac](https://github.com/minty江/unluac)就是这样一个强大的工具,它是一个专为Lua 5.1设计的反编译器。 ### 1、项目介绍 `unluac` 是一个基于Java开发的LUA 5.1反编译器,它可以将已编译的LUA字节码还原成易于...

gitblog_00046的博客 2239

Android 车载开发深度解析:CarPropertyManager 核心机制与实践指南

摘要: Android Automotive OS中,CarPropertyManager作为车载信息娱乐系统的核心组件,连接应用层与车辆硬件(如车速、油量等),其架构基于分层设计(App→CarAPI→VHAL→ECU),采用发布-订阅模式实现高效数据通信。通过HIDL/AIDL跨进程交互及共享内存优化,延迟可降至2ms以下。安全机制包括分级权限控制(VISIBLE/PROTECTED/SYSTEM_RESTRICTED)和HMAC防篡改。开发时需注意监听器生命周期管理、事件合并降负载及低功耗适配。

郑伟强dev的专栏 344

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

lua 调用文件中的函数调用_【Lua源码赏析】第一章 阅读源码准备

前言Lua作为游戏开发的吃饭语言,写了2、3年的lua,一行源码没看过,只能当个工具人,勉强维持生活。机缘巧合听了公司一个lua table源码解析的分享,感觉还蛮有意思,决定开始看一下lua源码,看懂这个我们开发使用的吃饭语言。【主要是闲了】该专栏其实就是云风 的 Lua源码赏析 读书笔记。1.1 目录下载到lua-5.2.1的源代码后,会发现源代码文件。全部放在src子目录下。这些文件根据实现...

weixin_39863161的博客 354

精雕软件(JDpaint) 5.5 绿色版

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

上一篇: RemDebug小巧的Lua远端调试器 告诉你coroutine很强大
下一篇: 根包含文件——Luaconf.h (src)收藏
skyremember
博客等级 码龄20年 204粉丝 484原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值