使用管道将大型 C 结构体直接传递给 Python

使用管道将大型 C 结构体直接传递给 Python

本教程旨在指导开发者如何通过管道将 C 语言结构体数据直接传递到 Python 脚本中进行处理。我们将详细介绍如何在 C 代码中使用 fwrite 将结构体数据写入标准输出,然后在 Python 中使用 subprocess 模块捕获输出,并利用 ctypes 模块将字节流解析为 Python 中的结构体对象。通过这种方法,可以实现高效的跨语言数据传输,避免中间文件,提高程序运行效率。

C 代码:将结构体数据写入标准输出

首先,我们需要在 C 代码中定义结构体,填充数据,然后使用 fwrite 函数将结构体数组的数据写入标准输出。 关键点在于包含 <stdio.h> 头文件,它包含了 fwrite 和 stdout 的声明。

#include <stdio.h> #include <stdlib.h>  struct ChemicalDemands {     double DO;     double BOD;     int time; };  int main() {     // 创建结构体数组     struct ChemicalDemands ChemicalDemands[3];      for (int i = 0; i < 3; i++) {         ChemicalDemands[i].DO = 1.0;         ChemicalDemands[i].BOD = 1.0;         ChemicalDemands[i].time = i;     }      // 将数据写入标准输出     fwrite(ChemicalDemands, sizeof(struct ChemicalDemands), 3, stdout);     return 0; }

注意事项:

  • 务必包含 <stdio.h> 头文件,否则 fwrite 和 stdout 将未定义,导致编译错误
  • 使用编译器警告标志(如 -Wall, -Wextra, -Wpedantic)可以帮助你发现潜在的问题。不要忽略警告,尝试理解并解决它们。

Python 代码:读取管道数据并解析

接下来,我们需要编写 Python 代码来捕获 C 程序的标准输出,并将其解析为 Python 中的结构体对象。

立即学习Python免费学习笔记(深入)”;

import subprocess import ctypes import sys  # 定义与 C 结构体对应的 Python 结构体 class Results(ctypes.Structure):     _fields_ = [("DO", ctypes.c_double),                 ("BOD", ctypes.c_double),                 ("time", ctypes.c_int)]  # 执行 C 程序并捕获输出 result = subprocess.run(["./a.out"], capture_output=True)  if result.returncode != 0:     print("Error:", result.stderr.decode())     sys.exit(1)  buffer = result.stdout  # 确定数组中的元素数量 num_elements = 3  # 从缓冲区创建 ctypes 数组 results_array = (Results * num_elements).from_buffer_copy(buffer)  # 打印第一个元素以验证数据是否正确 print(results_array[0].DO, results_array[0].BOD, results_array[0].time)

代码解释:

  1. ctypes 模块: ctypes 模块允许 Python 调用 C 动态链接库中的函数,并且可以定义与 C 结构体对应的 Python 类。
  2. Results 类: Results 类定义了与 C 结构体 ChemicalDemands 相同的字段,并且指定了每个字段的类型。 确保 Python 结构体的定义与 C 结构体的定义完全匹配,包括字段顺序和数据类型。
  3. subprocess.run 函数: subprocess.run 函数执行 C 程序,并捕获其标准输出和标准错误。
  4. capture_output=True: 这个参数确保标准输出和标准错误都被捕获。
  5. result.stdout: result.stdout 包含了 C 程序的标准输出,以字节流的形式存在。
  6. *`(Results num_elements):** 这创建了一个ctypes数组类型,其中Results是数组元素的类型,num_elements` 是数组的长度。
  7. .from_buffer_copy(buffer): 这个方法从缓冲区 buffer 中复制数据到 ctypes 数组中。

注意事项:

  • C 结构体和 Python 结构体的定义必须完全一致,包括字段类型和顺序。
  • 确保 C 程序编译后生成的可执行文件(例如 a.out)在 Python 脚本的同一目录下,或者在系统的 PATH 环境变量中。
  • num_elements 变量需要正确设置,以匹配 C 程序中写入的结构体数量。
  • 错误处理:检查 subprocess.run 的返回值,确保 C 程序成功执行。

总结

通过本教程,你学会了如何使用管道将 C 结构体数据直接传递到 Python 脚本中。这种方法可以避免中间文件,提高数据传输效率,特别适用于需要频繁进行跨语言数据交换的场景。记住,关键在于确保 C 结构体和 Python 结构体的定义一致,以及正确处理字节流数据。

python ai 编译错误 Python 数据类型 结构体 对象

上一篇
下一篇