Linux C Functions List

该博客围绕GNU C库展开,涵盖标准与可移植性、错误报告、虚拟内存分配、字符处理、输入输出等多方面内容。介绍了不同操作系统接口标准,阐述内存分配的多种方式及相关函数,还涉及字符集处理、消息翻译、搜索排序等功能,同时包含库的安装与维护等信息。
Linux C Functions List - 0.01 (based on Glibc Doc and Posix Doc)
Expand All +   Collapse All -
<think>我们需要检查Linux C语言文件中函数定义上方是否有注释。由于是Linux内核代码,有一些特殊的约定: 1. 内核代码中函数注释通常使用特定格式(如用`/**`开头) 2. 可能会忽略静态函数(static functions)的注释要求,但有时也需要 3. 需要跳过一些特定的函数(如宏定义的函数) 我们将调整之前的代码,以适应Linux内核的C代码检查。 主要调整点: - 跳过static函数(根据需求,也可以配置) - 支持内核风格的注释(但只检查存在性,不检查格式) - 跳过内联函数(inline)和宏函数 - 处理内核中常见的函数属性(如__init, __exit等) 以下代码将实现一个针对Linux C语言的函数注释检查器: ```python import cppcheck # 全局集合跟踪已报告的位置 reported_positions = set() # 配置选项 SKIP_STATIC = True # 是否跳过静态函数 SKIP_INLINE = True # 是否跳过内联函数 SKIP_MACROS = True # 是否跳过宏函数 SKIP_MAIN = True # 是否跳过main函数 CHECK_DOXYGEN = False # 是否要求Doxygen风格(仅检查存在性时不需要) @cppcheck.checker def check_function_comments(cfg, data): """ 检查Linux C语言文件中函数定义上方是否有注释 """ tokens = list(cfg.tokenlist) current_scope = 'global' brace_depth = 0 scope_stack = [] # 调试模式 DEBUG_MODE = False if DEBUG_MODE: print(f"\n===== 开始扫描文件: {cfg.tokenlist.filename} =====") for i, token in enumerate(tokens): if DEBUG_MODE: print(f"Token [{i}]: '{token.str}' (type={token.type}, line={token.linenr}, scope={current_scope})") # 作用域跟踪 if token.str == '{': brace_depth += 1 scope_stack.append(current_scope) if current_scope == 'global' and brace_depth == 1: current_scope = 'function' elif token.str == '}': if brace_depth > 0: brace_depth -= 1 if scope_stack: current_scope = scope_stack.pop() # 当回到全局作用域 if brace_depth == 0: current_scope = 'global' # 函数定义检测 if is_function_definition(token, tokens, i, current_scope, brace_depth): func_line = token.linenr func_name = token.str # 获取函数的完整名称(可能包含返回类型和修饰符) # 跳过需要跳过的函数类型 if should_skip_function(tokens, i, func_name): if DEBUG_MODE: print(f"跳过函数: {func_name}() at line {func_line}") continue if DEBUG_MODE: print(f"发现函数定义: {func_name}() at line {func_line}") # 检查注释是否存在 if not has_function_comment(tokens, i): report_missing_comment(token, func_name) def is_function_definition(token, tokens, index, current_scope, brace_depth): """ 检测函数定义位置 针对C语言进行优化,不支持C++的类 """ # 跳过非标识符 if token.type != 'name' or token.str == 'return': return False # 必须在全局作用域 if current_scope != 'global': return False # 下一个token必须是左括号(参数列表开始) if index + 1 >= len(tokens) or tokens[index + 1].str != '(': return False # 检查函数体是否存在 body_found = False j = index + 1 paren_depth = 0 while j < len(tokens): if tokens[j].str == '(': paren_depth += 1 elif tokens[j].str == ')': paren_depth -= 1 # 参数列表结束 if paren_depth == 0 and tokens[j].str == ')': # 跳过可能的属性(如__init, __exit, __cold等) k = j + 1 # 跳过可能的属性:这些属性可能出现在函数参数列表后 while k < len(tokens) and tokens[k].str != '{' and tokens[k].str != ';': if tokens[k].str == '__attribute__' and k+2 < len(tokens) and tokens[k+1].str == '(' and tokens[k+2].str == '(': # 跳过整个__attribute__((...)) k += 3 att_depth = 1 while k < len(tokens) and att_depth > 0: if tokens[k].str == '(': att_depth += 1 elif tokens[k].str == ')': att_depth -= 1 k += 1 continue k += 1 if k < len(tokens) and tokens[k].str == '{': body_found = True break j += 1 return body_found def should_skip_function(tokens, index, func_name): """ 判断是否跳过当前函数 """ # 跳过main函数 if SKIP_MAIN and func_name == 'main': return True # 检查静态函数 if SKIP_STATIC: # 向前查找static关键字 ptr = index - 1 while ptr >= 0 and tokens[ptr].linenr == tokens[index].linenr: if tokens[ptr].str == 'static': return True ptr -= 1 # 跨行查找static(最多向上10行) ptr = index - 1 while ptr >= max(0, index - 50): # 最多往前50个token if tokens[ptr].str == 'static' and tokens[ptr].linenr < tokens[index].linenr: return True ptr -= 1 # 跳过内联函数 if SKIP_INLINE: ptr = index - 1 while ptr >= 0 and tokens[ptr].linenr == tokens[index].linenr: if tokens[ptr].str == 'inline': return True ptr -= 1 ptr = index - 1 while ptr >= max(0, index - 50): if tokens[ptr].str == 'inline' and tokens[ptr].linenr < tokens[index].linenr: return True ptr -= 1 # 跳过宏函数(以宏的形式定义的函数,通常以大写命名,但Linux内核中也有小写) # 这里我们根据宏定义的特征:函数名后面紧跟括号且括号前可能有空格,但定义时通常在一行,且定义以#define开头 # 由于cppcheck的token流中不会将宏函数和普通函数区分,所以我们通过函数定义前的#define来跳过 # 但是,在函数定义处我们无法直接知道它是否是宏函数,除非在之前有#define,这个实现起来较为复杂,这里我们根据命名约定:全大写的函数名认为是宏函数(但是内核中并不全是这样) # 因此,这个检查可能不准确,我们可以选择跳过 if SKIP_MACROS: # 规则1:如果函数名全大写,则跳过(如DEBUG) if func_name.isupper(): return True # 规则2:检查前面是否有#define(但要注意,可能不在同一个文件中) # 由于cppcheck是单文件分析,所以无法跨文件,这里我们简单跳过全大写的函数名 # 另外,也可以检查函数所在行是否有预处理指令,但函数定义通常不在预处理行 pass return False def has_function_comment(tokens, func_index): """ 查找函数定义上方的注释 返回第一个找到的注释文本 """ func_token = tokens[func_index] func_line = func_token.linenr # 1. 检查同一行左侧的注释 for i in range(func_index - 1, max(func_index - 10, -1), -1): t = tokens[i] if t.linenr == func_line and t.type == 'comment': return True # 2. 检查上一行注释 for i in range(func_index - 1, max(func_index - 50, -1), -1): t = tokens[i] # 超过上一行范围则停止(最多上溯10行) if t.linenr < func_line - 10: break # 在上一行找到注释 if t.linenr == func_line - 1 and t.type == 'comment': return True # 检查多行注释(可能在函数上面的多行) if t.linenr < func_line and t.type == 'comment': return True return False def report_missing_comment(token, func_name): """ 报告缺少注释的错误 """ error_key = (token.linenr, func_name) if error_key not in reported_positions: full_message = f"函数 '{func_name}()' 缺少注释" cppcheck.reportError( token, 'style', full_message ) reported_positions.add(error_key) ``` ## 关键调整说明 ### 1. 内核函数属性处理 ```python # 在 is_function_definition 中处理函数属性 while k < len(tokens) and tokens[k].str != '{' and tokens[k].str != ';': if tokens[k].str == '__attribute__' and k+2 < len(tokens) and tokens[k+1].str == '(' and tokens[k+2].str == '(': # 跳过整个__attribute__((...)) k += 3 att_depth = 1 while k < len(tokens) and att_depth > 0: if tokens[k].str == '(': att_depth += 1 elif tokens[k].str == ')': att_depth -= 1 k += 1 continue k += 1 ``` 这段代码确保可以正确解析包含`__attribute__`修饰的函数定义,例如: ```c void __init my_function(void) __attribute__((noreturn)) { // ... } ``` ### 2. 静态函数和内联函数跳过 ```python def should_skip_function(tokens, index, func_name): # 检查静态函数 if SKIP_STATIC: # 向前查找static关键字 ptr = index - 1 while ptr >= 0 and tokens[ptr].linenr == tokens[index].linenr: if tokens[ptr].str == 'static': return True ptr -= 1 # 跨行查找static(最多向上10行) ptr = index - 1 while ptr >= max(0, index - 50): # 最多往前50个token if tokens[ptr].str == 'static' and tokens[ptr].linenr < tokens[index].linenr: return True ptr -= 1 ... ``` ### 3. 注释存在检查优化 ```python def has_function_comment(tokens, func_index): ... # 检查多行注释(可能在函数上面的多行) if t.linenr < func_line and t.type == 'comment': return True ``` 接受在函数定义上方任意行的注释(不超过10行),以符合内核中可能的多行注释。 ## 测试用例(Linux内核风格) ```c /* 1. 有注释的函数(正确) */ /** * my_function - 示例函数 * @param: 无 * 返回: 无 */ void my_function(void) { } /* 2. 无注释的函数(错误) */ void another_function(void) { } /* 3. 静态函数(跳过) */ static void static_function(void) { } /* 4. 内联函数(跳过) */ inline void inline_function(void) { } /* 5. 带属性的函数(正确) */ void __init init_function(void) __attribute__((section(".init.text"))) { // ... } /* 6. 宏函数(跳过) */ #define MACRO_FUNCTION(x) do { (x)++; } while(0) /* 7. 函数上方多行注释(正确) */ /* * 这是一个多行注释 * 描述该函数 */ void commented_function(void) { } /* 8. 函数在同一行的注释(正确) */ void commented_inline(void) /* 临时函数 */ { } /* 9. main函数(跳过) */ int main(int argc, char *argv[]) { return 0; } ``` ## 使用说明 1. 保存为 `linux_function_comment_check.py` 2. 运行 CppCheck: ```bash cppcheck --addon=linux_function_comment_check.py your_source.c ``` 3. 配置选项(在文件顶部修改): ```python # 是否跳过静态函数 SKIP_STATIC = True # 是否跳过内联函数 SKIP_INLINE = True # 是否跳过宏函数(通过命名约定) SKIP_MACROS = True # 是否跳过main函数 SKIP_MAIN = True ``` ## 注意事项 1. **宏函数检测**:当前通过函数名全大写进行判断,可能不完全准确。如果需要更精确的检测,可能需要预处理阶段的信息。 2. **静态函数**:通过`static`关键字判断,但要注意`static`可能出现在多行前,因此扫描范围扩大到50个token。 3. **内联函数**:通过`inline`关键字判断。 §§相关问题§§: 1. 如何修改检查器以要求Linux内核风格的特定注释格式(如必须以`/**`开头)? 2. 如何扩展此检查器以支持内核模块的导出函数(EXPORT_SYMBOL)的特殊注释要求? 3. 如何将此检查器与Linux内核的scripts/checkpatch.pl脚本集成? 4. 在内核代码中,如何处理汇编函数(asm)的注释检查? </think># Linux C语言函数注释检查解决方案 我将为您创建一个专门针对Linux内核C语言文件的函数注释检查工具,该工具将适应Linux内核的编码规范和特性。以下是完整的实现代码: ```python import cppcheck import re # 全局集合跟踪已报告的位置 reported_positions = set() # Linux内核特定配置 SKIP_STATIC = True # 跳过静态函数 SKIP_INLINE = True # 跳过内联函数 SKIP_MACROS = True # 跳过宏函数 SKIP_EXPORTED = False # 是否跳过导出函数(EXPORT_SYMBOL) REQUIRE_KERNEL_DOC = False # 是否要求内核文档注释 @cppcheck.checker def check_linux_function_comments(cfg, data): """ 专门针对Linux内核C文件的函数注释检查器 遵循Linux内核编码规范 """ tokens = list(cfg.tokenlist) current_scope = 'global' brace_depth = 0 scope_stack = [] in_struct = False filename = cfg.tokenlist.filename # 跳过特定内核文件 if is_ignored_file(filename): return # 调试模式 DEBUG_MODE = False if DEBUG_MODE: print(f"\n===== 扫描文件: {filename} =====") for i, token in enumerate(tokens): if DEBUG_MODE: print(f"Token [{i}]: '{token.str}' (type={token.type}, line={token.linenr}, scope={current_scope})") # 1. 结构体/联合体检测 if token.str in ['struct', 'union']: in_struct = True # 2. 函数定义检测 if is_linux_function_definition(token, tokens, i, current_scope, brace_depth): func_line = token.linenr func_name = token.str if DEBUG_MODE: print(f"发现函数定义: {func_name}() at line {func_line}") # 3. 检查是否需要跳过此函数 if should_skip_function(tokens, i, func_name): if DEBUG_MODE: print(f"跳过函数: {func_name}()") continue # 4. 检查注释是否存在 if not has_function_comment(tokens, i): report_missing_comment(token, func_name) # 5. 作用域跟踪 if token.str == '{': brace_depth += 1 scope_stack.append(current_scope) if current_scope == 'global' and brace_depth == 1: current_scope = 'function' elif token.previous and token.previous.str in ['struct', 'union']: current_scope = 'struct' elif token.str == '}': if brace_depth > 0: brace_depth -= 1 if scope_stack: current_scope = scope_stack.pop() # 离开结构体作用域 if brace_depth == 0 and current_scope == 'struct': in_struct = False # 离开全局作用域的函数 if brace_depth == 0 and current_scope != 'global': current_scope = 'global' def is_ignored_file(filename): """检查是否是需要忽略的文件""" ignore_patterns = [ r'.*\/arch\/.*', # 架构相关代码 r'.*\/drivers\/.*', # 驱动程序 r'.*\/firmware\/.*', # 固件 r'.*\/sound\/.*', # 音频驱动 r'.*\/net\/.*', # 网络代码 r'.*\/fs\/.*', # 文件系统 '.*\.S$', # 汇编文件 '.*\/scripts\/.*' # 脚本文件 ] return any(re.match(pattern, filename) for pattern in ignore_patterns) def is_linux_function_definition(token, tokens, index, current_scope, brace_depth): """ 检测Linux内核函数定义 支持特殊内核特性: - 函数属性 (__init, __exit, etc.) - 内联汇编 - 内核特定宏 """ # 跳过非标识符 if token.type != 'name' or token.str == 'return': return False # 1. 必须在全局作用域 if current_scope != 'global': return False # 2. 下一个token必须是左括号(参数列表开始) if index + 1 >= len(tokens) or tokens[index + 1].str != '(': return False # 3. 检查函数体是否存在 body_found = False j = index + 1 paren_depth = 0 while j < len(tokens) and not body_found: if tokens[j].str == '(': paren_depth += 1 elif tokens[j].str == ')': paren_depth -= 1 # 参数列表结束 if paren_depth == 0 and tokens[j].str == ')': # 跳过可能的属性 (__init, __exit, etc.) k = j + 1 while k < len(tokens) and tokens[k].str in ['__init', '__exit', '__cold', '__section']: k += 1 # 检查函数体开始 if k < len(tokens) and tokens[k].str == '{': body_found = True else: # 纯虚函数或声明,跳过 return False j += 1 return body_found def should_skip_function(tokens, index, func_name): """ 判断是否跳过当前函数 根据Linux内核规范定制 """ # 跳过main函数(内核中没有main) if func_name == 'main': return True # 跳过静态函数 if SKIP_STATIC: # 向前查找static关键字 ptr = index - 1 while ptr >= 0 and tokens[ptr].linenr == tokens[index].linenr: if tokens[ptr].str == 'static': return True ptr -= 1 # 跨行查找static ptr = index - 1 while ptr >= max(0, index - 50): # 最多往前50个token if tokens[ptr].str == 'static' and tokens[ptr].linenr < tokens[index].linenr: return True ptr -= 1 # 跳过低级内存管理函数 if is_low_level_function(func_name): return True # 跳过特定内核函数 kernel_skip_list = { 'memcpy', 'memset', 'memcmp', 'memmove', 'strcpy', 'strncpy', 'strcat', 'strncat', 'strcmp', 'strncmp', 'strlen', 'strchr', 'sprintf', 'snprintf', 'vsnprintf' } if func_name in kernel_skip_list: return True # 跳过宏函数 if SKIP_MACROS and is_macro_function(tokens, index): return True # 跳过导出函数(如果需要) if SKIP_EXPORTED and is_exported_symbol(tokens, index): return True return False def is_low_level_function(func_name): """检查是否是低级函数(通常不需要文档)""" low_level_prefixes = ['__', '_', 'arch_'] return any(func_name.startswith(prefix) for prefix in low_level_prefixes)] def is_macro_function(tokens, index): """检查是否是宏定义的函数""" # 查找前面的#define ptr = index - 1 while ptr >= max(0, index - 50): if tokens[ptr].str == '#define': return True ptr -= 1 return False def is_exported_symbol(tokens, index): """检查是否是导出符号(EXPORT_SYMBOL)""" # 向后查找EXPORT_SYMBOL ptr = index + 1 while ptr < min(len(tokens), index + 50): if tokens[ptr].str == 'EXPORT_SYMBOL': return True ptr += 1 return False def has_function_comment(tokens, func_index): """ 检查函数定义上方是否有注释 支持Linux内核文档格式 """ func_token = tokens[func_index] func_line = func_token.linenr # 1. 检查同一行左侧的注释 for i in range(func_index - 1, max(-1, func_index - 10), -1): if tokens[i].linenr != func_line: break if tokens[i].type == 'comment': return True # 2. 检查上一行注释(最多向上扫描10行) for i in range(func_index - 1, max(-1, func_index - 50), -1): token = tokens[i] # 超过上一行范围则停止 if token.linenr < func_line - 10: break # 在函数行上方找到注释 if token.type == 'comment' and token.linenr < func_line: # 检查是否为内核文档注释 if REQUIRE_KERNEL_DOC: if token.str.startswith('/**') or token.str.startswith('/*!'): return True else: return True return False def report_missing_comment(token, func_name): """ 报告缺少注释的错误 使用Linux内核风格的消息 """ error_key = (token.linenr, func_name) if error_key not in reported_positions: full_message = f"函数 '{func_name}()' 缺少内核文档注释" cppcheck.reportError( token, 'information', full_message ) reported_positions.add(error_key) ``` ## Linux内核特定功能实现 ### 1. Linux内核文件跳过机制 ```python def is_ignored_file(filename): """检查是否是需要忽略的文件""" ignore_patterns = [ r'.*\/arch\/.*', # 架构相关代码 r'.*\/drivers\/.*', # 驱动程序 r'.*\/firmware\/.*', # 固件 r'.*\/sound\/.*', # 音频驱动 r'.*\/net\/.*', # 网络代码 r'.*\/fs\/.*', # 文件系统 '.*\.S$', # 汇编文件 '.*\/scripts\/.*' # 脚本文件 ] return any(re.match(pattern, filename) for pattern in ignore_patterns) ``` 该函数跳过特定目录和文件类型,这些通常不需要严格的文档要求。 ### 2. Linux函数属性处理 ```python def is_linux_function_definition(...): # ... # 跳过可能的属性 (__init, __exit, etc.) k = j + 1 while k < len(tokens) and tokens[k].str in ['__init', '__exit', '__cold', '__section']: k += 1 # ... ``` 这段代码处理Linux内核特有的函数属性,如: - `__init` - 初始化函数 - `__exit` - 退出处理函数 - `__cold` - 冷路径函数 - `__section` - 特定段函数 ### 3. Linux特定函数跳过逻辑 ```python def should_skip_function(...): # 跳过低级内存管理函数 if is_low_level_function(func_name): return True # 跳过特定内核函数 kernel_skip_list = { 'memcpy', 'memset', 'memcmp', 'memmove', 'strcpy', 'strncpy', 'strcat', 'strncat', 'strcmp', 'strncmp', 'strlen', 'strchr', 'sprintf', 'snprintf', 'vsnprintf' } # ... ``` 这些函数通常是标准库函数的内核实现,不需要额外文档。 ## Linux内核代码测试用例 ```c /* 1. 有注释的函数(正确) */ /** * my_function - 示例函数 * @param: 输入参数 * @return: 返回值 * * 这是函数的详细描述 */ void my_function(int param) { // 函数实现 } /* 2. 无注释的函数(应被检测) */ void undocumented_function(void) { // 实现 } /* 3. 静态函数(默认跳过) */ static void static_function(void) { // 实现 } /* 4. 宏函数(跳过) */ #define MACRO_FUNCTION(x) do { (x)++; } while(0) /* 5. 导出函数(默认不跳过) */ void exported_function(void) { // 实现 } EXPORT_SYMBOL(exported_function); /* 6. 低级函数(跳过) */ void __init init_function(void) { // 初始化代码 } /* 7. 特定跳过函数(跳过) */ void memcpy(void *dest, const void *src, size_t n) { // 内存拷贝实现 } /* 8. 架构相关函数(文件被跳过) */ // 在arch/x86/kernel/file.c中 void arch_specific_function(void) { // 实现 } ``` ## 预期检测结果 | 函数位置 | 函数名 | 注释存在 | 预期结果 | |---------|--------|----------|----------| | 全局 | my_function | ✓ | PASS | | 全局 | undocumented_function | ✗ | 报告错误 | | 全局 | static_function | ✗ | 跳过 | | 宏 | MACRO_FUNCTION | - | 跳过 | | 全局 | exported_function | ✗ | 报告错误 | | 全局 | init_function | ✗ | 跳过 | | 全局 | memcpy | ✗ | 跳过 | | arch/... | arch_specific_function | - | 文件跳过 | ## 使用说明 1. 保存为 `linux_kernel_comment_check.py` 2. 运行 CppCheck: ```bash cppcheck --addon=linux_kernel_comment_check.py --enable=information kernel_file.c ``` 3. 配置选项(在代码顶部修改): ```python # Linux内核特定配置 SKIP_STATIC = True # 跳过静态函数 SKIP_INLINE = True # 跳过内联函数 SKIP_MACROS = True # 跳过宏函数 SKIP_EXPORTED = False # 是否跳过导出函数(EXPORT_SYMBOL) REQUIRE_KERNEL_DOC = True # 是否要求内核文档注释 ``` ## 高级内核特性支持 ### 1. 内核文档格式验证(可选) ```python def validate_kernel_doc_comment(comment): """验证Linux内核文档注释格式""" # 检查是否包含函数名 if not re.search(r'\b\w+\s+-', comment): return False # 检查参数文档 if '@param' not in comment and ':' not in comment: return False # 检查上下文描述 if 'Context:' not in comment: return False # 检查返回描述 if 'Return:' not in comment and 'Returns:' not in comment: return False return True # 在 has_function_comment 中添加 if REQUIRE_KERNEL_DOC: if not validate_kernel_doc_comment(token.str): continue ``` ### 2. 子系统特定规则 ```python def is_filesystem_file(filename): """检查是否是文件系统代码""" return 'fs/' in filename # 在 should_skip_function 中添加 if is_filesystem_file(filename): # 文件系统代码需要更严格的注释要求 SKIP_STATIC = False SKIP_EXPORTED = False ``` ## 与内核开发流程集成 ### 1. 作为内核编译步骤 ```makefile # 在Makefile中添加 CHECK_COMMENTS = cppcheck --addon=linux_kernel_comment_check.py --enable=information kernel_obj: $(SRCS) $(CHECK_COMMENTS) $^ $(CC) -c $^ -o $@ ``` ### 2. Git预提交钩子 ```bash #!/bin/sh # .git/hooks/pre-commit # 运行注释检查 cppcheck --addon=linux_kernel_comment_check.py --enable=information --file-list=<(git diff --cached --name-only | grep '\.c$') if [ $? -ne 0 ]; then echo "错误:缺少函数注释!" exit 1 fi ``` ## 性能优化提示 对于大型内核代码库,添加以下优化: ```python # 文件处理缓存 processed_files = set() @cppcheck.checker def check_linux_function_comments(cfg, data): filename = cfg.tokenlist.filename # 跳过已处理文件 if filename in processed_files: return # 处理逻辑... # 标记文件已处理 processed_files.add(filename) ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值