news 2026/6/9 22:07:37

12.15 脚本工具 找c函数原型

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
12.15 脚本工具 找c函数原型

一 场景,我们在阅读源码的时候,

c默认调用看不到函数类型,函数返回值,所以需要查看函数原型。

二 功能,脚本是批量寻找所有引入的文件。 将函数调用和函数原型放在一起。

三,使用,termux 或linux,

cd... ,py ... 即可,它会提示你输入文件.c ,提示输入项目根目录。 会自动在根目录生成分析报告。

这里为什么不用人工智能?因为人工智能输出不固定,

四,代码

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ C函数定义与原型对比分析工具 用于分析C源文件中的函数定义,并在头文件中查找对应的原型声明 """ import os import re import sys from pathlib import Path import clang.cindex as CX # ---------- 配置 ---------- try: libclang_paths = [ 'libclang.so', '/usr/lib/x86_64-linux-gnu/libclang.so', '/usr/lib/llvm-15/lib/libclang.so', '/usr/lib64/libclang.so', '/usr/lib/libclang.so', '/usr/local/opt/llvm/lib/libclang.dylib' # macOS ] for path in libclang_paths: if os.path.exists(path): CX.Config.set_library_file(path) print("已找到并使用 libclang: " + path) break else: print("警告:未能自动找到 libclang。请确保已安装 libclang 并设置正确路径。") except Exception as e: print("配置 libclang 时出错: " + str(e)) # -------------------------- # 1. 生成Markdown代码块分隔符 def get_fence(): """返回三个反引号,用于生成Markdown代码块""" return chr(96) + chr(96) + chr(96) # 2. 用户输入辅助函数 def ask(prompt): """获取用户输入并去除首尾空格""" return input(prompt).strip() # 3. 收集项目中的所有头文件 def collect_headers(root: Path): """递归收集项目根目录下的所有.h头文件""" return list(root.rglob('*.h')) # 4. 解析C文件中的函数定义 def parse_c_file_definitions(c_path: Path): """ 使用libclang解析C文件,提取所有函数定义 参数: c_path: C源文件路径 返回: 字典,键为函数名,值为包含签名和位置的字典 """ func_defs = {} try: index = CX.Index.create() # 添加编译参数,包含系统头文件路径 args = ['-x', 'c', '-I/usr/include', '-I/usr/local/include'] tu = index.parse(str(c_path), args=args) if not tu: print("错误:无法解析文件 " + str(c_path)) return {} # 遍历抽象语法树 for cursor in tu.cursor.walk_preorder(): if cursor.kind == CX.CursorKind.FUNCTION_DECL and cursor.is_definition(): name = cursor.spelling # 过滤无效函数 if not name or not cursor.location.file: continue # 确保函数定义在当前文件中 if not str(c_path).endswith(cursor.location.file.name): continue # 获取位置信息 loc = str(Path(cursor.location.file.name).name) + ":" + str(cursor.location.line) # 使用libclang获取完整的函数签名 try: # 获取函数类型 func_type = cursor.type return_type = func_type.get_result().spelling # 获取参数列表 args_list = [] for arg in cursor.get_arguments(): arg_type = arg.type.spelling args_list.append(f"{arg_type} {arg.spelling}" if arg.spelling else arg_type) # 构建完整的函数签名 args_str = ", ".join(args_list) if args_list else "void" signature = f"{return_type} {name}({args_str})" func_defs[name] = {'signature': signature, 'loc': loc} except Exception as e: print("警告:获取函数签名失败: " + str(e)) except Exception as e: print("解析C文件时出错: " + str(e)) return func_defs # 5. 在头文件中查找函数原型 def find_prototype_in_headers(func_name, header_paths, c_path): """ 在头文件中搜索指定函数的原型声明 参数: func_name: 函数名 header_paths: 头文件路径列表 c_path: C源文件路径(用于排除自身) 返回: (原型字符串, 位置字符串) 或 (None, None) """ # 改进的正则表达式,更准确地匹配函数原型 # 匹配:返回类型 + 函数名 + 参数列表 + 分号 pattern = re.compile( r'^\s*(?:extern\s+|static\s+|inline\s+)*' # 可选的存储类说明符 r'(?:[\w\s\*]+\s+)' # 返回类型(包含指针修饰符) r'\b' + re.escape(func_name) + r'\s*' # 函数名 r'\([^;{]*\)\s*;' # 参数列表和分号 ) # 特殊处理:main函数通常不需要原型 if func_name == 'main': return None, None for h_path in header_paths: # 跳过C文件本身 if h_path == c_path: continue try: with open(h_path, 'r', encoding='utf-8', errors='ignore') as f: for line_num, line in enumerate(f, 1): # 移除行尾注释 line_clean = line.split('//')[0].strip() if pattern.search(line_clean): prototype_line = line_clean location = str(Path(h_path).relative_to(h_path.parents[2])) + ":" + str(line_num) return prototype_line, location except Exception as e: print(f"警告:读取头文件 {h_path} 失败: {str(e)}") return None, None # 6. 生成对比报告 def build_report(c_path, func_defs, header_paths): """ 生成函数定义与原型对比的Markdown格式报告 参数: c_path: C源文件路径 func_defs: 函数定义字典 header_paths: 头文件路径列表 返回: Markdown格式的报告内容 """ lines = [] # 报告标题 lines.append("# 函数定义与原型对比报告\n") lines.append(f"> 源文件:`{c_path}`\n") lines.append("---\n") # 检查是否找到函数定义 if not func_defs: lines.append("在源文件中未找到任何函数定义。") return "\n".join(lines) # 为每个函数生成对比部分 for i, (name, info) in enumerate(sorted(func_defs.items()), 1): lines.append(f"### {i}. 函数定义") lines.append(get_fence() + "c") lines.append(info['signature']) lines.append(get_fence()) lines.append(f"*定义位置:{info['loc']}*") lines.append("\n**🔍 对应原型**") # 在头文件中查找原型 prototype_line, location = find_prototype_in_headers(name, header_paths, c_path) if prototype_line: lines.append(get_fence() + "c") lines.append(prototype_line) lines.append(get_fence()) lines.append(f"*原型位置:{location}*") else: # 特殊说明 if name == 'main': lines.append("*`main` 函数是程序入口点,通常不需要在头文件中声明原型。*") else: lines.append("*未在项目头文件中找到匹配的原型。*") lines.append("\n---\n") return "\n".join(lines) # 7. 主程序入口 def main(): """主程序,协调整个分析流程""" # 获取C文件路径 c_file = Path(ask("请输入 .c 文件路径:")).expanduser().resolve() if not c_file.exists() or c_file.suffix != '.c': sys.exit("错误:文件不存在或不是 .c 后缀") # 获取项目根目录 proj_root = Path(ask("请输入项目根目录:")).expanduser().resolve() if not proj_root.is_dir(): sys.exit("错误:项目根目录不存在") # 收集头文件 header_paths = collect_headers(proj_root) if not header_paths: print("警告:在项目根目录下未找到任何 .h 文件。") # 解析C文件 print("正在解析 C 文件...") func_defs = parse_c_file_definitions(c_file) if not func_defs: sys.exit("在指定的 C 文件中未找到任何函数定义,分析结束。") # 生成报告 print("正在生成报告...") report_content = build_report(c_file, func_defs, header_paths) # 保存报告 report_dir = proj_root / "analysis_report" report_dir.mkdir(exist_ok=True) report_file = report_dir / (c_file.stem + "_vs_prototype.md") try: report_file.write_text(report_content, encoding='utf-8') print(f"\n✅ 分析完成!报告已生成:\n{report_file}") except Exception as e: print(f"\n❌ 写入报告文件失败: {str(e)}") if __name__ == '__main__': main()
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 11:17:10

AutoGPT能否胜任项目经理角色?任务分配能力检验

AutoGPT能否胜任项目经理角色?任务分配能力检验 在一家科技公司准备发布新产品前的晨会上,项目经理正对着白板列出几十项待办事项:市场调研、竞品分析、推广渠道筛选、预算分配……整个规划过程耗时整整两天,团队反复开会确认细节…

作者头像 李华
网站建设 2026/6/9 20:29:27

11、深入了解 Linux 根文件系统

深入了解 Linux 根文件系统 1. 根文件系统概述 根文件系统是 Linux 系统的重要组成部分,它包含了系统启动和运行所需的基本文件和目录结构。了解根文件系统的结构、内容以及与 Linux 内核的交互方式,对于开发人员和系统管理员来说至关重要。 在嵌入式环境开发中,传统方式…

作者头像 李华
网站建设 2026/6/10 6:48:24

1×9光模块:经典设计的传承与精准选型指南

在千兆与万兆光模块主导市场的今天,一款被称为“9针模块”的19光模块依然以其独特的焊接式设计和经久不性的可靠性,活跃在特定的工业与通信领域。它不追求热插拔的便捷,却以极致的稳定性和简化的电路集成,成为许多关键系统的基石。…

作者头像 李华
网站建设 2026/6/10 4:47:37

C++实现D星 Lite算法

D* Lite算法核心概念 D* Lite是一种增量式的路径规划算法,适用于动态环境,能够高效地重新规划路径,而无需每次都从头开始计算。下表汇总了其实现中的关键数据结构与核心函数:组件类型名称说明关键数据结构优先队列 (U)存储待处理的…

作者头像 李华
网站建设 2026/6/10 7:35:43

37、运动中的意象与催眠:提升表现的有效策略

运动中的意象与催眠:提升表现的有效策略 1. 意象与运动表现的关系 在运动领域,意象与表现之间以及意象能力与表现之间存在着一定的联系。然而,意象使用和意象能力之间的相互作用并不显著,没有证据表明意象能力会调节意象使用与田径表现之间的关系。研究者认为,客观表现的…

作者头像 李华