Linux常用工具

Linux常用工具

本节内容
  • 了解yum工具,进行软件安装
  • vim编辑器适用,学会vim简单配置
  • gcc/g++编译器,了解过程,原理
  • 掌握简单gdb适用于调试
  • 掌握简单的makefile编写,了解其运行思想
  • 编写第一个Linux程序–进度条
  • 了解git命令行的简单操作,传入github
工具分类
  • 软件包管理工具—yum
  • 个人编辑工具—vim(编辑器),gcc/g++(编译器),gdb(调试器)
  • 项目的管理工具—make/Makefile(项目的自动化构建工具),git(项目的版本管理工具)
Linux软件包管理器 yum
什么是软件包?
  • 在Linux下安装软件,一个通常的办法是下载到程序的源代码,并进行编译,得到可执行程序.
  • 但是这样太麻烦了, 于是有些人把一些常用的软件提前编译好,做成软件包(可以理解成windows上的安装程序)放在一个服务器上,通过包管理器可以很方便的获取到这个编译好的软件包, 直接进行安装.软件包和软件包管理器,就好比"App"和"应用商店"这样的关系.
  • yum是Linux下非常常用的一种包管理器.主要应用在Fedora,RedHat,Centos等发行版上.
关于 lrzsz(主机与虚拟机之间的文件传输工具)
  • 在终端敲下rz,就会弹出一个小框框,这个工具用于windows机器和远端的Linux机器通过 XShell传输文件.安装完毕之后可以通过拖拽的方式将文件上传过去.
  • 反之,敲下sz,是从虚拟机向windows主机传输文件,传文件的时候需要选择要传到哪里,在使用sz的时候需要指定要传输文件的文件名
查看软件包
  • 通过 yum list 命令可以罗列出当前一共有哪些软件包.(默认去centos官方服务器去请求当前版本的centos能够安装哪些软件包),也可以使用yum search +关键字 去查找
  • 由于包的数目可能非常之多, 这里我们需要使用 grep 命令只筛选出我们关注的包.
  • eg: yum list | grep lrzsz(利用管道连接符)
  • yum的命令形式一般是如下:yum [options] [command] [package …]
    其中的[options]是可选的,选项包括-h(帮助),-y(当安装过程提示选择全部为"yes"),-q(不显示安装的过程)等等。[command]为所要进行的操作,[package …]是操作的对象。
如何安装软件
  • 通过 yum, 我们可以通过很简单的一条命令完成 gcc 的安装.
  • eg: yum install gcc
  • yum 会自动找到都有哪些软件包需要下载, 这时候敲 “y” 确认安装.出现 “complete” 字样, 说明安装完成.
  • yum install 全部安装
  • yum install package1 安装指定的安装包package1
  • yum groupinsall group1 安装程序组group1
  • yum update 全部更新
  • yum update package1 更新指定程序包package1
注意事项:
  • 安装软件时由于需要向系统目录中写入内容,一般需要su或者切到root账户下才能完成.
  • yum安装软件只能一个装完了再装另一个.,如果再尝试用yum安装另外一个软件,yum会报错.
如何查看已经安装了哪些安装包
  • 使用yum list installed
如何卸载软件
  • yum remove lrzsz(同样需要切换管理员用户)
注意事项:
  • 软件包名称: 主版本号.次版本号.源程序发行号-软件包的发行号.主机平台.cpu架构.
  • “x86_64” 后缀表示64位系统的安装包, “i686” 后缀表示32位系统安装包. 选择包时要和系统匹配.
  • “el7” 表示操作系统发行版的版本. “el7” 表示的是 centos7/redhat7. “el6” 表示 centos6/redhat6.
  • 最后一列, base 表示的是 “软件源” 的名称, 类似于 “小米应用商店”, “华为应用商店” 这样的概念.
Linux编辑器—vim使用
  • vi/vim的区别简单点来说,它们都是多模式编辑器,不同的是vim是vi的升级版本,它不仅兼容vi的所有指令,而且还有一些新的特性在里面。例如语法加亮,可视化操作不仅可以在终端运行,也可以运行于x window、 mac os、windows。
  • vim—命令行下的文本编辑工具
  • 文本编辑:插入数据/复制/剪切/删除/保存/退出编辑
  • vim默认不支持鼠标操作/并且默认没有windonw下常用快捷键,比如ctrl+c,crtl+v
vim的模式(一共有12种操作模式,常用的3种)
  • vim有多种不同的操作模式,不同的操作模式下某个按键的功能也会有所不同
  • 正常/普通/命令模式—控制屏幕光标的移动,字符、字或行的删除,移动复制某区段及进入Insert mode下,或者到lastlinemode(打开时候默认的模式,功能是完成文本内容的操作:—复制粘贴删除)
  • 插入模式—只有在Insertmode下,才可以做文字输入,按「ESC」键可回到命令行模式。该模式是我们后面用的最频繁的编辑模式
  • 底行/末行模式—文件保存或退出,也可以进行文件替换,找字符串,列出行号等操作。在命令模式下,shift+: 即可进入该模式。要查看你的所有模式:打开vim,底行模式直接输入(文本的保存以及退出编辑)
  • vim test.c (这个test.c可以不存在,vim会自动创建这个文件)–打开一个文件
模式之间的切换
  • 普通模式到插入模式,使用i,但是使用i输入,是在当前光标所处的位置进行输入;也可以使用a,光标向后移动一个字符,然后开始插入,当然a的时候也可以随意挪动光标所在的位置;使用小写o,在光标所在行下方添加新行,开始插入.(有小写的iao,也有大写的IAO,功能可能会不同,A,光标移动到行尾开始输入)
  • 按「i」切换进入插入模式,按“i”进入插入模式后是从光标当前位置开始输入文件
  • 按「a」进入插入模式后,是从目前光标所在位置的下一个位置开始输入文字;
  • 按「o」进入插入模式后,是插入新的一行,从行首开始输入文字。
  • 插入模式到普通模式,使用ESC.不管在什么模式下,按ESC总能返回普通模式
  • 普通模式到底行模式,使用:
  • 如何保存退出—回到普通模式,按一个冒号:进入底行模式,然后按w,:w是保存数据,:q是退出,:wq,是保存并退出 :q! 不保存,强制退出
vim普通模式下的操作
光标的移动
  • vim可以直接用键盘上的光标来上下左右移动,但正规的vim是用小写英文字母h、j、k、l,分别控制光标左、下、上、右移一格
  • ctrl+f,ctrl+b 向前,向后翻页,ctrl+f屏幕向前移动一页,ctrl+b屏幕向后移动一页
  • G—直接跳转到文件末尾
  • gg—跳转到首行,也就是进入文本开始
  • gg=G,全文对齐
  • 按$ :移动到光标所在行的行尾
  • 按^ :移动到光标所在行的行首
  • 按w :光标跳到下个字的开头
  • 按e :光标跳到下个字的字尾
文本基本操作—复制/粘贴/剪切/删除
复制操作
  • Linux下基本都是按行复制,如果需要进行复制的话,那么需要在普通模式种按下yy,就已经复制了,然后按p是粘贴到光标所在的下一行,P是向上粘贴,p是向下粘贴。如果想多行复制,就按下nyy,意思是复制n行的内容
  • p :将缓冲区内的字符贴到光标所在位置。注意:所有与“y”有关的复制命令都必须与“p”配合才能完成复制与粘贴功能。在光标所在行的下一行进行粘贴操作
删除操作
  • dd—删除光标所在行,在vim中,其实没有真正的删除,其实是剪切操作
  • ndd—从光标所在行就开始删除,一共删除n行的内容
  • x—删除光标所在处的字符
  • dw—删除单词
  • nx—例如 6x 表示删除光标所在位置的后面(包含自己在内)6个字符
其他操作
撤销上一次操作
  • u: 如果您误执行一个命令,可以马上按u,回到上一个操作。按多次“u”可以执行多次回
    复。
  • ctrl + r :撤销的恢复,也就是反向的撤销
Linux编译器—gcc/g++的使用
  • 编译器—我们所写的C语言代码,是不能被机器直接识别的。因为C语言是一个高级语言,所写的代码不是一个机器能够识别的指令,因此这个时候就需要编译器来将这些高级语言所写的代码翻译为机器能够识别的指令集
  • gcc是C语言的编译器,g++是C++语言的编译器
  • 编译器其实也是一个程序
背景知识

编译器将高级语言代码解释成为机器指令集所经过的过程:

  • 预处理(进行宏替换)
  • 编译(生成汇编)
  • 汇编(生成机器可识别代码)
  • 连接(生成可执行文件或库文件)
    在这里插入图片描述
预处理
预处理(宏替换,头文件引入,去掉注释)
  • 预处理功能主要包括宏定义,文件包含,条件编译,去注释等。
  • 预处理指令是以#号开头的代码行。
  • 实例: gcc –E hello.c –o hello.i
  • 选项“-E”,该选项的作用是让 gcc 在预处理结束后停止编译过程。
  • 选项“-o”是指目标文件,“.i”文件为已经过预处理的C原始程序。
  • 代码有没有错误,在于处理就阶段是不关注的,就算有错误也不会报错,只是展开所有代码
  • 实例子—gcc -E test.c -o test.i,
  • 生成的test.i文件中就是展开的东西,包括头文件的展开
编译(生成汇编)—进行代码语法语义纠错,没错则将C语言程序解释成为汇编指令
  • 在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言。
  • 用户可以使用“-S”选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。
  • 实例: gcc –S hello.i –o hello.s,生成的.s文件里面全死汇编指令
汇编(生成机器可识别代码)—将汇编指令解释成为机器可以识别的指令,但是这时候生成的也不能直接运行,因为是不完整的。
  • 汇编阶段是把编译阶段生成的“.s”文件转成目标文件
  • 读者在此可使用选项“-c”就可看到汇编代码已转化为“.o”的二进制目标代码了
  • 实例: gcc –c hello.s –o hello.o -c是只进行汇编
链接(生成可执行文件或库文件)—将所有代码都打包到一起,最终生成可执行程序
  • 在成功编译之后,就进入了链接阶段。
  • 实例: gcc hello.o –o hello
函数库
  • 我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实“printf”函数的呢?
  • 最后的答案是:系统把这些函数实现都被做到名为libc.so.6的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用
  • 库是写好的,现有的,成熟的,可以复用的代码。现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。
  • 本质上来说,库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。库有两种:静态库(.a、.lib)和动态库(.so、.dll)。
  • 所谓静态、动态是指链接。回顾一下,将一个程序编译成可执行程序的步骤:
    *
函数库一般分为静态库和动态库两种
  • 静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为“.a”
  • 动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,如前面所述的 libc.so.6就是动态库。gcc在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件,如下所示。gcchello.o –o hello
  • gcc默认生成的二进制程序,是动态链接的,这点可以通过file 命令验证。
静态库
  • 之所以称为【静态库】,是因为在链接阶段,会将汇编生成的目标文件.obj与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接。
  • 试想一下,静态库与汇编生成的目标文件一起链接为可执行文件,那么静态库必定跟.obj文件格式相似。其实一个静态库可以简单看成是一组目标文件(.o/.obj文件)的集合,即很多目标文件经过压缩打包后形成的一个文件。静态库特点总结如下:
  • 1.静态库对函数库的链接是放在编译时期完成的。
  • 2.程序在运行时与函数库再无瓜葛,移植方便。
  • 3.浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。
    在这里插入图片描述
动态库
  • 为什么还需要动态库?----空间浪费是静态库的一个问题。
    *在这里插入图片描述
  • 动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。动态库在程序运行时才被载入,也解决了静态库对程序的更新、部署和发布页会带来麻烦。用户只需要更新动态库即可,增量更新。
    在这里插入图片描述
  • 动态库特点总结:
  • 1.动态库把对一些库函数的链接载入推迟到程序运行的时期。
  • 2.可以实现进程之间的资源共享。(因此动态库也称为共享库)
  • 3.将一些程序升级变得简单。
  • 4.甚至可以真正做到链接载入完全由程序员在程序代码中控制(显示调用)。

静态库的代码在编译过程中已经被载入可执行程序,因此体积比较大。

动态库(共享库)的代码在可执行程序运行时才载入内存,在编译过程中仅简单的引用,因此代码体积比较小。

链接方式—链接实际上就是把其他的代码都拿过来生成可执行程序
  • 动态链接—在生成可执行程序文件中并不写入具体库种函数的实现代码,而是在可执行程序文件中记录了函数符号信息表,好处就是生成的可执行程序文件比较小,但是因为可执行程序中没有这些代码,因此运行程序的时候不但要加载可执行程序,而且还要去加这个库到内存中,但是这种方式也有一个好处:多个程序在内存中可以使用同一个库(两个程序都用了C库,只需要加载一份到内存中就可以了),内存中代码冗比较少。
  • 静态链接—在生成可执行程序的时候,直接将库种的代码写入到了可执行程序文件中,因此运行程序的时候就不需要加载文件库了,但是如果多个程序都使用了同一个库,则会在内存中造成代码冗余
  • gcc默认使用动态链接
Linux调试器—gdb使用

调试器:调试一个程序的运行过程

  • 调试一个程序,则这个程序中必须包含调试符号信息,然而gcc编译器,在编译程序生成可执行程序的时候,默认生成的是release版本,其中不包含调试符号信息,因此,想要体哦啊是程序,首先在gcc编译的时候使用-g选项生成debug版本程序(程序可以进行调试的前提就是,这个程序是debug版本的程序)
  • gdb调试器–调试程序的运行过程,便于找出程序中bug出现的位置,调试一个程序的前提是,这个程序要处于debug版本,程序中要包含调试信息的符号,gcc -g test.c -o test
  • gdb ./test
  • 转到代码的反汇编
    在这里插入图片描述
背景
  • 程序的发布方式有两种,debug模式和release模式
  • Linux gcc/g++出来的二进制程序,默认是release模式
  • 要使用gdb调试,必须在源代码生成二进制程序的时候, 加上-g 选项(因为只有处于debug模式下的程序才可以进行调试)
  • gdb调试原理:调研ptrace接口
gdb调试程序运行过程的命令
开始调试命令
  • run—直接运行程序 r或run:运行程序
  • start—开始逐步调试,在终端输入start,会显示出main函数的第一行,就可以看到main函数第一行的内容了
  • gdb -p pid 调试运行中的程序
流程相关命令
  • list—查看当前调试行附近的代码
  • list/l 行号:显示binFile源代码,接着上次的位置往下列,每次列10行。
  • 因为start是逐行调试的,那么如何查看下一步呢,查看下一步,就使用next,或者n,是他的简写 n 或 next:单条执行。
  • next是下一步,step也是下一步,两个的区别在于:next下一步是遇到函数直接运行完毕;step的下一步是遇到函数会跟踪进函数,但是一般只能跟踪进,我们自己写的函数,库函数是无法跟踪进入下一步的 s或step:进入函数调用
  • until +行号—直接跳转到程序的某一行,比如until test.c:20直接跳转到程序的第20行
  • 如果不想继续调试也不想重新开始运行,那么就是用continue,意思是从当前位置开始连续而非但不执行程序 continue(或c)(不再逐步调试,继续运行)
断点相关命令
  • break—打断点,举个例子,break test.c:行数,就是在第几行的位置打下一个断点,就是说,程序运行到这里就会停下,然后在手动去向下进行( break(b) 行号:在某一行设置断点 )
  • info break 查看断点信息
  • delete break删除断点(delete break_id—删除你想要删除的断点) delete 5 就是删除5号断点
  • 如果程序走到断点的位置,此时他停下来了,如果你不想继续调试,你当然也可以使用continue
  • watch变量监控断点,watch后面加上你希望监控的变量的名称
  • print:打印变量的内容
    在这里插入图片描述
    在这里插入图片描述
其他命令
  • 如何快速定位程序崩溃退出的的原因—查看函数调用栈—backtrace,就可以看出函数是在哪里出问题的了。
  • 为什么查看函数的调用栈就可以快速定位函数崩溃退出的原因呢?
    在这里插入图片描述
    在这里插入图片描述
  • 一般察看函数运行时堆栈的方法是使用GDB(bt命令)之类的外部调试器,但是,有些时候为了分析程序的BUG,(主要针对长时间运行程序的分析),在程序出错时打印出函数的调用堆栈是非常有用的。
  • int backtrace(void *buffer,int size) —该函数用于获取当前线程的调用堆栈,获取的信息将会被存放在buffer中,它是一个指针列表。参数 size 用来指定buffer中可以保存多少个void 元素。函数返回值是实际获取的指针个数,最大不超过size大小
Linux项目自动化构建工具-make/Makefile
背景
  • 会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力
  • 一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作
  • makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编
    译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,VisualC++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。
  • make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。
  • Makefile—是一个普通的文本文件,这个文件中记录着一个项目的编译流程以及规则
  • make—是Makefile的解释器(make是一个程序),他会找到Makefile文件,按照逐行解释执行其中记录的项目构建规则,最终完成项目的构建
  • 所以make/Makefile要说的就是Makefile的编写规则以及make的解释执行规则
Makefile的编写规则
hello:hello.o
    gcc hello.o -o hello
hello.o:hello.s
    gcc -c hello.s -o hello.o
hello.s:hello.i
    gcc -S hello.i -o hello.s
hello.i:hello.c
    gcc -E hello.c -o hello.i
test:test.c
    gcc test.c -o test
(保存并退出就可以了)
make就是找到目标对象,去执行指令
依赖关系
  • 上面的文件hello(也就是即将要生成的文件),它依赖hell.o
  • hello.o , 它依赖hello.s hello.s , 它依赖hello.i
  • hello.i , 它依赖hello.c
依赖方法
  • gcc hello.* -option hello.* ,就是与之对应的依赖关系
预定义变量—make中预先定义好的变量,通常是使用在命令中的变量
  • $^----所有的依赖对象
  • $<—依赖对象的第一个
  • $@—目标对象
    在这里插入图片描述
  • Linux下#是注释
  • 如果make已经生成一次了的话,再使用一次make就会出现如下的信息:
    在这里插入图片描述
  • 就不需要重新生成了,系统会自动进行检测,那么系统是如何进行检测的呢?就是比较目标对象的时间和以来对象的时间,看谁更接近当前的时间,谁更接近当前的时候就说明谁是最新的,也就是说从上一次之后就再也没有被更改过了,所以说他是最新的了,就不需要去虫子你生成了
声明伪对象—伪对象是每次都要重新生成的目标对象
  • 伪对象—每次都要重新生成的目标对象 .PHONY:后面是对象的名称
  • 也就是用PHONY声明的每一次都会重新生成,不管是否最新不管是否存在,都会重新生成
    在这里插入图片描述
原理在这里插入图片描述
make是如何工作的

make是如何工作的,在默认的方式下,也就是我们只输入make命令。那么

  • make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
  • 如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“hello”这个文件,并把这个文件作为最终的目标文件。
  • 如果hello文件不存在,或是hello所依赖的后面的hello.o文件的文件修改时间要比hello这个文件新(可以用touch 测试),那么,他就会执行后面所定义的命令来生成hello这个文件。
  • 如果hello所依赖的hello.o文件不存在,那么make会在当前文件中找目标为hello.o文件的依赖性,如果找到则再根据那一个规则生成hello.o文件。(这有点像一个堆栈的过程)
  • 当然,你的C文件和H文件是存在的啦,于是make会生成 hello.o 文件,然后再用 hello.o 文件声明
    make的终极任务,也就是执行文件hello了。
  • 这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。
  • 在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。
  • make只管文件的依赖性,即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就不工作啦。
    在这里插入图片描述
make的执行规则
  • 可以理解成一个递归的过程
  • 但是如果多个目标对象依赖于同一个依赖对象的话,那么他只会生成第一个目标对象
  • 总之,make只会生成第一个目标对象
    在这里插入图片描述
    在这里插入图片描述
项目清理
  • 工程是需要被清理的
  • 像clean这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,不过,我们可以显示要make执行。即命令——“make clean”,以此来清除所有的目标文件,以便重编译。
  • 但是一般我们这种clean的目标文件,我们将它设置为伪目标,用.PHONY修饰,伪目标的特性是,总是被执行的。
  • 可以将我们的hello 目标文件声明成伪目标,测试一下。
编写一个进度条程序代码

在这里插入图片描述

  • 为什么printf中打印的数据不加换行会导致数据不能第一时间显示出来—原因是
    在这里插入图片描述
  • 前提是只有在标准输出文件中,换行才有特殊的作用,在普通文件中,换行是没有特殊作用的。普通文件的操作,换行是没有刷新缓冲区的作用的
  • \r是回车符,使得光标回到行首
  • fflush的作用是刷新缓冲区的作用
    在这里插入图片描述
  • 原因:只有stdout的缓冲区是通过‘\n’进行行刷新的,但是我开始的时候就把stdout就关闭了,就会像普通文件一样像文件中写,所以‘\n’是不会行刷新的,所以要使用fflush(stdout)。
  • stderr无缓冲,不用经过fflush或exit,就直接打印出来
  • stdout行缓冲 遇到\n刷新缓冲区
使用 git 命令行
安装 git
  • yum install git
三板斧第一招:
  • git add [文件名]
三板斧第二招:
  • git commit.
  • 最后的 “.” 表示当前目录提交的时候应该注明提交日志, 描述改动的详细内容.
三板斧第三招:
  • git push
  • 需要填入用户名密码. 同步成功后, 刷新 Github 页面就能看到代码改动了

复习:
在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值