windows和Linux内存的对齐方式

如何申请对齐的动态内存? windows下有现成的函数:_align_malloc, _align_realloc, _align_free,_align_offset_malloc,_aligned_offset_realloc     见     http://msdn.microsoft.com/zh-tw/data/8z34s9c6      以及      http://msdn.microsoft.c 阅读详情

一.内存对齐的初步解说

内存对齐能够用一句话来概括:

“数据项仅仅能存储在地址是数据项大小的整数倍的内存位置上”

比如int类型占用4个字节,地址仅仅能在0,4,8等位置上。

 

 

例1:

#include <stdio.h>
struct xx{
        char b;
        int a;
        int c;
        char d;
};

int main()
{
        struct xx bb;
        printf("&a = %p\n", &bb.a);
        printf("&b = %p\n", &bb.b);
        printf("&c = %p\n", &bb.c);
        printf("&d = %p\n", &bb.d);
        printf("sizeof(xx) = %d\n", sizeof(struct xx));

        return 0;
}

运行结果例如以下:

&a = ffbff5ec
&b = ffbff5e8
&c = ffbff5f0
&d = ffbff5f4
sizeof(xx) = 16

会发现b与a之间空出了3个字节。也就是说在b之后的0xffbff5e9,0xffbff5ea,0xffbff5eb空了出来,a直接存储在了0xffbff5ec。 由于a的大小是4。仅仅能存储在4个整数倍的位置上。打印xx的大小会发现,是16。有些人可能要问,b之后空出了3个字节,那也应该是13啊?其余的3个 呢?这个往后阅读本文会理解的更深入一点,这里简单说一下就是d后边的3个字节。也会浪费掉。也就是说,这3个字节也被这个结构体占用了.

能够简单的改动结构体的结构。来减少内存的使用,比如能够将结构体定义为:
struct xx{
        char b; 
        char d;
        int a;          
        int c;                  
};

这样打印这个结构体的大小就是12。省了非常多空间,能够看出。在定义结构体的时候。一定要考虑要内存对齐的影响,这样能使我们的程序占用更小的内存。

 

 

二.操作系统的默认对齐系数

每 个操作系统都有自己的默认内存对齐系数,假设是新版本号的操作系统,默认对齐系数一般都是8,由于操作系统定义的最大类型存储单元就是8个字节,比如 long long(为什么一定要这样。在第三节会解说)。不存在超过8个字节的类型(比如int是4,char是1,long在32位编译时是4,64位编译时是 8)。当操作系统的默认对齐系数与第一节所讲的内存对齐的理论产生冲突时。以操作系统的对齐系数为基准。

 

 

比如:

如果操作系统的默认对齐系数是4,那么对与long long这个类型的变量就不满足第一节所说的,也就是说long long这样的结构,能够存储在被4整除的位置上,也能够存储在被8整除的位置上。

能够通过#pragma pack()语句改动操作系统的默认对齐系数,编敲代码的时候不建议改动默认对齐系数,在第三节会解说原因

例2:

#include <stdio.h>
#pragma pack(4)
struct xx{
        char b;
        long long a;
        int c;
        char d;
};
#pragma pack()

int main()
{
        struct xx bb;
        printf("&a = %p\n", &bb.a);
        printf("&b = %p\n", &bb.b);
        printf("&c = %p\n", &bb.c);
        printf("&d = %p\n", &bb.d);
        printf("sizeof(xx) = %d\n", sizeof(struct xx));

        return 0;
}
打印结果为:

&a = ffbff5e4
&b = ffbff5e0
&c = ffbff5ec
&d = ffbff5f0
sizeof(xx) = 20

发现占用8个字节的a,存储在了不能被8整除的位置上。存储在了被4整除的位置上。採取了操作系统的默认对齐系数。

三.内存对齐产生的原因

 


内存对齐是操作系统为了高速訪问内存而採取的一种策略,简单来说,就是为了放置变量的二次訪问。操作系统在訪问内存 时,每次读取一定的长度(这个长度就是操作系统的默认对齐系数,或者是默认对齐系数的整数倍)。假设没有内存对齐时,为了读取一个变量是,会产生总线的二 次訪问。

比如如果没有内存对齐。结构体xx的变量位置会出现例如以下情况:

struct xx{
        char b;         //0xffbff5e8
        int a;            //0xffbff5e9       
        int c;             //0xffbff5ed      
        char d;         //0xffbff5f1
};

操作系统先读取0xffbff5e8-0xffbff5ef的内存,然后在读取0xffbff5f0-0xffbff5f8的内存,为了获得值c,就须要将两组内存合并,进行整合。这样严重减少了内存的訪问效率。(这就涉及到了老生常谈的问题,空间和效率哪个更重要?这里不做讨论)。

这样大家就能理解为什么结构体的第一个变量,无论类型怎样,都是能被8整除的吧(由于訪问内存是从8的整数倍開始的,为了添加读取的效率)!


内存对齐的问题主要存在于理解struct等复合结构在内存中的分布。

首先要明确内存对齐的概念。

 


很多实际的计算机系统对基本类型数据在内存中存放的位置有限制。它们会要求这些数据的首地址的值是某个数k(通常它为4或8)的倍数。这就是所谓的内存对齐。

 

这个k在不同的cpu平台下,不同的编译器下表现也有所不同。比方32位字长的计算机与16位字长的计算机。这个离我们有些远了。

 

我们的开发主要涉及两大平台。windows和linux(unix)。涉及的编译器也主要是microsoft编译器(如cl),和gcc。

内存对齐的目的是使各个基本数据类型的首地址为相应k的倍数,这是理解内存对齐方式的终极法宝。另外还要区分编译器的分别。

 

明确了这两点基本上就能搞定全部内存对齐方面的问题。

 

不同编译器中的k:
1、对于microsoft的编译器,每种基本类型的大小即为这个k。大体上char类型为8。int为32,long为32。double为64。
2、对于linux下的gcc编译器,规定大小小于等于2的。k值为其大小,大于等于4的为4。

明确了以上的说明对struct等复合结构的内存分布就应该非常清楚了。

以下看一下最简单的一个类型:struct中成员都为基本数据类型。比如:
struct test1
{
char a;
short b;
int c;
long d;
double e;
};

在windows平台,microsoft编译器下:

如果从0地址開始,首先a的k值为1,它的首地址能够使任何位置。所以a占用第一个字节。即地址0;然后b的k值为2,他的首地址必须是2的倍数,不能是1,所以地址1那个字节被填充。b首地址为地址2,占用地址2,3;然后到c,c的k值为4,他的首地址为4的倍数。所以首地址为4,占用地址4,5。6。7。再然后到d,d的k值也为4。所以他的首地址为8,占用地址8,9。10,11。

 

最后到e,他的k值为8。首地址为8的倍数,所以地址12,13,14。15被填充。他的首地址应为16,占用地址16-23。显然其大小为24。

这就是 test1在内存中的分布情况。我们建立一个test1类型的变量,a、b、c、d、e分别赋值2、4、8、16、32。

 

然后从低地址依次打印出内存中每一个字节相应的16进制数为:
2 0 4 0 8 0 0 0 10 0 0 0 0 0 0 0 0 0 0 0 0 0 40 40

验证:
显然判断是正确的。

 

 

在linux平台,gcc编译器下:
如果从0地址開始。首先a的k值为1,它的首地址能够使任何位置,所以a占用第一个字节。即地址0。然后b的k值为2,他的首地址必须是2的倍数。不能是1。所以地址1那个字节被填充,b首地址为地址2,占用地址2。3;然后到c。c的k值为4。他的首地址为4的倍数,所以首地址为4。占用地址4。5,6。7;再然后到d,d的k值也为4。所以他的首地址为8,占用地址8,9。10。11。

 

最后到e,从这里開始与microsoft的编译器開始有所差异,他的k值为不是8,仍然是4,所以其首地址是12,占用地址12-19。显然其大小为20。

验证:
我们建立一个test1类型的变量。a、b、c、d、e分别赋值2、4、8、16、32。

 

然后从低地址依次打印出内存中每一个字节相应的16进制数为:
2 0 4 0 8 0 0 0 10 0 0 0 0 0 0 0 0 0 40 40

显然判断也是正确的。

接下来,看一看几类特殊的情况。为了避免麻烦。不再描写叙述内存分布,仅仅计算结构大小。

第一种:嵌套的结构
struct test2
{
char f;
struct test1 g;
};

在windows平台。microsoft编译器下:

这样的情况下假设把test2的第二个成员拆开来,研究内存分布,那么能够知道,test2的成员f占用地址0。g.a占用地址1,以后的内存分布不变,仍然满足全部基本数据成员的首地址都为其相应k的倍数这一原则,那么test2的大小就还是24了。可是实际上test2的大小为32。这是由于:不能由于test2的结构而改变test1的内存分布情况。所以为了使test1种各个成员仍然满足对齐的要求,f成员后面须要填充一定数量的字节,不难发现。这个数量应为7个,才干保证test1的对齐。所以test2相对于test1来说添加了8个字节,所以test2的大小为32。

 

 

在linux平台,gcc编译器下:

相同,这样的情况下假设把test2的第二个成员拆开来,研究内存分布,那么能够知道,test2的成员f占用地址0,g.a占用地址1,以后的内存分布不变,仍然满足全部基本数据成员的首地址都为其相应k的倍数这一原则,那么test2的大小就还是20了。可是实际上test2的大小为24,相同这是由于:不能由于test2的结构而改变test1的内存分布情况,所以为了使test1种各个成员仍然满足对齐的要求,f成员后面须要填充一定数量的字节,不难发现,这个数量应为3个。才干保证test1的对齐。

 

所以test2相对于test1来说添加了4个字节,所以test2的大小为24。

 

另外一种:位段对齐

struct test3
{
unsigned int a:4;
unsigned int b:4;
char c;
};
或者
struct test3
{
unsigned int a:4;
int b:4;
char c;
};

在windows平台,microsoft编译器下:

相邻的多个同类型的数(带符号的与不带符号的,仅仅要基本类型同样。也为同样的数),假设他们占用的位数不超过基本类型的大小。那么他们可作为一个总体来看待。不同类型的数要遵循各自的对齐方式。
如:test3中。a、b可作为一个总体。他们作为一个int型数据来看待,所以test3的大小为8字节。而且a与b的值在内存中从低位開始依次排列,位于4字节区域中的前0-3位和4-7位

假设test4位下面格式
struct test4
{
unsigned int a:30;
unsigned int b:4;
char c;
};
那么test4的大小就为12个字节,而且a与b的值分别分布在第一个4字节的前30位。和第二个4字节的前4位。

 

 

如过test5是下面形式
struct test5
{
unsigned int a:4;
unsigned char b:4;
char c;
};

那么因为int和char不同类型。他们分别以各自的方式对齐,所以test5的大小应为8字节,a与b的值分别位于第一个4字节的前4位和第5个字节的前4位。

在linux平台。gcc编译器下:

struct test3
{
unsigned int a:4;
unsigned int b:4;
char c;
};
gcc下,相邻各成员。无论类型是否同样。占的位数之和超过这些成员中第一个的大小的时候,在结构中以k值为1对齐,在结构外k值为其基本类型的值。

 

不超过的情况下在内存中依次排列。


如test3。其大小为4。a,b的值在内存中依次排列分别为第一个四字节中的0-3和4-7位。

 

假设test4位下面格式
struct test4
{
unsigned int a:20;
unsigned char b:4;
char c;
};
test4的大小为4个字节,而且a与b的值分别分布在第一个4字节的0-19位,和20-23位,c存放在第4个字节中。
如过test5是下面形式
struct test5
{
unsigned int a:10;
unsigned char b:4;
short c;
};

那么test5的大小应为4字节,a。b的值为0-9位和10-13位。c存放在后两个字节中。

 

假设a的大小变成了20
那么test5的大小应为8字节。

即

struct test6
{
unsigned int a:20;
unsigned char b:4;
short c;
};

此时,test6的a、b共占用0,1,2共3字节,c的k值为2,事实上能够4位首位置,可是在结构外,a要以int的方式对齐。也就是说连续两个test6对象在内存中存放的话,a的首位置要保证为4的倍数。那么c后面必须多填充2位。所以test6的大小为8个字节。

关于位段结构的部分是比較复杂的。

WINDOWS和LINUX的内存防护机制 一、windows下的内存保护机制0x00、二进制漏洞二进制漏洞是可执行文件(PE、ELF文件等)因编码时考虑不周,造成的软件执行了非预期的功能。二进制漏洞早期主要以栈溢出为主。我们都知道在C语言中调用一个函数,在编译后执行的是CALL指令,CALL指令会执行两个操作:(1)、将CALL指令之后下一条指令入栈。 (2)、跳转到函数地址。函数在开始执行时主要工作为保存该函数会修改的寄存器的值和申请局 阅读详情

相关推荐

Windows和Linux下使用共享内存在C++和Python之间共享DataFrame

参考资料 windows api: https://docs.microsoft.com/en-us/windows/win32/api/ 《Linux-UNIX系统编程手册》 Python Doc: https://docs.python.org/3/library/mmap.html Linux manual: https://man7.org/linux/man-pages/man2/mmap.2.html 实现(windows) 主要功能 用C++创建共享内存,用Python进行读取,用csv格

WilliamCode的博客 4028

内存对齐问题

计算机的中内存对齐问题

a1164641067的博客 663

Edge主页被2345劫持?手动清理注册表与组策略的完整方案

浏览器主页劫持是Windows系统中常见的恶意篡改行为,其原理是通过修改注册表、快捷方式、组策略等多处系统配置,强制锁定浏览器启动页。这类劫持不仅影响上网体验,还可能带来隐私泄露和恶意软件感染风险。在安全防护与系统优化场景中,掌握手动清理主页劫持的技能至关重要。本文针对Edge主页被2345导航劫持的问题,深入解析劫持入口,提供从快捷方式、注册表到组策略的逐层清理步骤,并给出防复发策略,帮助用户彻底摆脱顽固劫持。

weixin_30582943的博客 380

内存对齐

一.内存对齐的初步讲解内存对齐可以用一句话来概括:“数据项只能存储在地址是数据项大小的整数倍的内存位置上”例如int类型占用4个字节,地址只能在0,4,8等位置上。例1:#include struct xx{        char b;        int a;        int c;        char d;};int main(){        str

1278

RabbitMQ的使用(JAVA)

Java快速上手的MQ上线!

.............. 1万+

STM32 移植LwIP 实现网线插拔自动恢复

STM32 移植LwIP 之后,能正常联网通讯,但是发现2个问题, 1、上电初始化前,未插入网线,之后就无法获取到IP地址(DHCP) 2、正常通讯过程中,拔掉网线,然后插回去,不知道如何复位 先看一下LWIP初始化代码 /** * LwIP initialization function */ int MX_LWIP_Init() { /* Initilialize the LwIP stack with RTOS */ tcpip_init( NULL, NULL );

tiantangmoke的博客 8073

Windows内存体系(6) -- 彻底理解内存对齐

一、内存为什么要对齐 虽然所有的变量都是保存在特定地址的内存中,但最好还是按照内存对齐的要求来存储。这主要出于两个方面的原因考虑: 平台原因: 不是所有的硬件平台(特别是嵌入式系统中使用的低端处理器)都能访问任意地址上的任意数据,某些硬件平台只能访问对齐的地址,否则会出现硬件异常。 性能原因: 如果数据存放在未对齐的内存空间中,则处理器访问变量时需要进行两次内存访问才能完整读取该...

while(1) { smile(); } 9万+

手把手教你学Simulink——基于Simulink的隔离型DC-DC全桥变换器移相控制建模示例

本文详细介绍了基于Simulink的全桥移相变换器(PSFB)建模与控制方法。首先分析了全桥移相拓扑在大功率应用中的优势,包括ZVS实现、高频化和小型化特点。随后给出了具体设计参数和移相控制策略,采用电压外环+移相角内环的双闭环控制架构。文章重点演示了Simulink建模步骤,包括主电路搭建、移相PWM生成和PI控制器设计,并通过满载稳态、负载阶跃和轻载测试三种场景验证了系统性能。最后总结了工程实践要点,提出自适应控制等扩展方向,强调移相控制通过精准时间管理实现高效能量转换的核心价值。

MHD0815的博客 261

结构体内存对齐

内存对齐:        目的:一来简化了处理器与内存之间传输系统的设计,二来可以提升读取数据的速度。         定义:许多实际的计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地址的值是某个数k(通常它为4或8)的倍数,这就是所谓的内存对齐,而这个k则被称为该数据类型的对齐模数(alignment modulus)。当一种类型S的对齐模数与另一种类型T的对齐模数

daisyZH的专栏 639

在 ABAP Cloud 中玩转 CL_ABAP_PARALLEL 并行处理:从原理到实战

ABAP并行处理框架CL_ABAP_PARALLEL解析 本文系统介绍了SAP ABAP环境中实现并行处理的CL_ABAP_PARALLEL框架。该框架通过封装异步RFC和对话进程,为开发者提供了面向对象的API,显著提升大批量数据处理的效率。 文章首先分析了ABAP环境需要并行处理的原因:传统的串行处理在面对百万级数据时效率低下。然后详细介绍了CL_ABAP_PARALLEL的设计思路,它是一个"小型线程池"式的同步并行框架,适用于批量计算场景。此外,文章重点讲解了控制并行任务的关键参

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 338

Python爬取马蜂窝旅游攻略详细实战指南

马蜂窝是国内非常知名的旅游攻略网站,包含了大量的景点介绍、旅行攻略、游记等信息。爬取马蜂窝的数据对于旅游数据分析、旅游产品推荐等有重要价值。但由于马蜂窝对爬虫有一定的反爬措施,并且页面中大量内容通过JavaScript动态加载,爬虫难度相对较大。本篇博客将带你从零开始,使用Python和相关爬虫技术,逐步实现对马蜂窝旅游攻略内容的高效爬取。并结合实战经验,分析反爬策略,提供科学合理的绕过方案。本文介绍了马蜂窝攻略的结构和抓取难点。演示了静态+动态内容的混合爬取技术。介绍了多线程和异步加速方法。

2201_76125261的博客 587

windows、linux 字节对齐

《深入理解计算机系统》中写到 linux下 2字节类型的数据的地址必须是2的倍数,4,8字节类型的数据的地址必须是4的倍数;,windows  n个字节类型的数据的地址必须是n的倍数 但是我在64位的linux上,发现double是8字节对齐; k字节对齐,则结构体总大小要是k的倍数,不够的末尾补齐 #include #include #include /* 32位

le119126的专栏 2017

通过轻量级图像增强Transformer (IAT) 提升YOLOv8在低光环境下的检测性能

随着深度学习和计算机视觉的快速发展,目标检测模型在各个领域中的应用不断扩展,特别是在低照度环境下的视觉任务。YOLOv8作为当前最先进的目标检测模型之一,在高亮度和良好照明条件下表现出色,但在低照度环境下的性能存在一定的不足。为了解决这一问题,我们提出了一种轻量级的低照度图像增强网络(IAT)来改进YOLOv8的暗光检测能力。本篇文章将深入探讨这一创新改进,并附带代码实现,帮助大家更好地理解这一技术的应用和效果。

博客 1214

结构体大小和数据对齐原则

数据对齐:许多计算机系统对基本数据类型合法地址做出了一些限制,要求某种类型对象的地址必须是某个值K(通常是2,4或8)的倍数。这种对齐限制简化了形成处理器和存储器系统之间的接口的硬件设计。例如,假设一个处理器总是从存储器中取出8个字节,则地址必须为8的倍数。如果我们能保证将所有的double类型数据的地址对齐成8的倍数,那么就可以用一个存储器操作来读或者写值了。否则,我们可能需要执行两次存储器访问...

shuyuan0128的专栏 888

【python数据挖掘课程】二十八.基于LDA和pyLDAvis的主题挖掘及可视化分析

这是《Python数据挖掘课程》系列文章,前面很多文章都讲解了数据挖掘、机器学习,这篇文章主要讲解LDA和pyLDAvis算法,同时讲解如何读取CSV文本内容进行主题挖掘及可视化展示。文章比较基础,希望对你有所帮助,提供些思路,也是自己教学的内容。推荐大家购买作者新书《Python网络数据爬取及分析从入门到精通(分析篇)》,如果文章中存在错误或不足之处,还请海涵。 目录: 一.显示结果及安装 二.LDA主题挖掘 三.pyLDAvis可视化分析 四.小结

杨秀璋的专栏 1万+

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

内存对齐的原则是什么?

规则 1:成员按自身大小对齐。规则 2:结构体成员按其内部最大成员对齐。规则 3:整个结构体大小补齐为最大成员大小的整数倍。😀 关注 @公众号 程序员陈子青,获取更多 C++ 技术支持。

陈子青的博客 458

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

VB、C#、VC使用条件编译自动选择结构体对齐方式

VB、C#、VC使用条件编译使程序自动选择结构体对齐方式

中游鱼的博客 1557

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

计算机控制技术及应用

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

C++程序设计语言练习5.2 内存对齐

内存对齐

armor51的专栏 500

c语言内存对齐问题

#include <stdio.h> #pragma pack(4)struct stu{char a;short b;int c;char d;};int main(){printf("%d\n", sizeof(struct stu));return 0;}#pragma pack(4) // pack(n) n=2^n windows默认值8 linux 默认值是4 在c语言...

weixin_30439067的博客 90

Windows、Linux系统上进行CPU和内存压力测试

Linux环境下,我们可以用stress工具进行内存、CPU等的压力测试。

geriletuma 3545

Windows和Linux内存共享机制

在嵌入式开发领域,内存共享机制作为不同操作系统间实现高效数据交换的重要手段,尤其在对实时性和可靠性要求极高的环境中更为关键。本篇博客将深入探讨Windows和Linux各自的内存共享机制,结合ARINC 653标准在VxWorks中的实际应用,剖析其实现原理和实际使用中的关键技术,帮助读者更好地理解内存共享在跨平台环境中的应用场景与优势。

hu_yuchen的博客 1027

Java面试必备:Windows 和 Linux 操作系统虚拟内存机制比较

虚拟内存是现代操作系统的重要功能之一,它通过将物理内存和磁盘存储结合起来,为应用程序提供了比实际物理内存更大的地址空间。Windows 和 Linux 作为两大主流操作系统,在虚拟内存的实现上有着显著差异。本文将深入比较两者的虚拟内存机制。

qq_58299462的博客 2194

浅谈windows和linux下内存分配规律

首先先说明下,本文中代码来自牛刀教程。写的很不错。给我不少的启发。谢谢了 我们都知道,在使用C语言时,比如定义一个数组,一个变量。那么系统都会随机的分配内存。那么你知道内存分配的规律吗? 让我们用两个实验来说明windows和linux下,内存分配方式的不同。 同一个程序(如下) #include int main() { char ch1[] = {'A',

点滴 3415

Windows和Linux下共享内存使用

Windows和Linux下共享内存使用, 详细讲解了两个平台下共享内存的使用方法,以及使用的差异。

ylmbtm的专栏 2458
上一篇: gcc多版本安装
下一篇: DPDK
HideInTime
博客等级 码龄9年 86粉丝 131原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值