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/9 21:23:11

SAST、DAST、FOSS、SonarQube 企业级扫描工具解析

🚗 代码安全“四重安检”:你的软件真的安全吗? ——SAST、DAST、FOSS、SonarQube 企业级扫描工具全景解析🔍 引言:当开发像造一辆“数字汽车”想象一下,你正在制造一辆智能汽车: 🔧 …

作者头像 李华
网站建设 2026/6/9 21:22:24

基于遗传算法的33节点配电网网络重构MATLAB实现

1. 主程序文件 % 33节点配电网网络重构 - 遗传算法优化 clear; clc; close all;%% 参数设置 pop_size 50; % 种群大小 max_gen 100; % 最大迭代次数 pc 0.8; % 交叉概率 pm 0.1; % 变异概率 elite_rate 0.1; % 精英保…

作者头像 李华
网站建设 2026/6/8 15:14:10

Graph Unlearning---论文总结

一、研究背景 1、隐私法规与被遗忘权 近年来,随着《通用数据保护条例》(GDPR)、《加州消费者隐私法案》(CCPA)等法律法规的颁布,数据隐私保护成为了全球关注的焦点。其中最重要且最具争议的条款之一是 “…

作者头像 李华
网站建设 2026/6/9 19:40:55

Aave V4:从割裂市场到模块化流动性

撰文:Tia,Techub News 在 DeFi 借贷领域,Aave 一直是创新与行业标准的风向标。随着用户规模和资产种类的增长,Aave V3 逐渐暴露出流动性割裂、风险管理和清算机制相对粗糙的问题。为应对这些挑战,Aave V4 进行了系统性…

作者头像 李华
网站建设 2026/6/8 20:21:04

Kali_2025年最新版下载安装最全流程功能介绍(内附安装教程)

收藏必备!零基础也能学会的Kali Linux安装与使用指南,网络安全学习首选系统 文章主要介绍了Kali Linux这一基于Debian的安全专用操作系统,包含其特点(开源免费、支持无线注入、高度可定制等)、适用人群(渗透测试者、安全研究员等)以及安装步…

作者头像 李华
网站建设 2026/6/9 21:14:00

详谈:解释器模式(三)

我们接上文来继续讲:计算符怎么处理呢?计算符左右两边可能是单个数字,也可能是另一个计算公式。但无论是数字还是公式,两者都有一个共同点,那就是他们都会返回一个整数:数字返回其本身,公式返回…

作者头像 李华