首页电脑使用python和c++一起学会混淆吗 python和c++进程间通信

python和c++一起学会混淆吗 python和c++进程间通信

圆圆2025-11-20 15:02:00次浏览条评论

解决windows上python与c++子进程二进制数据通信的eof问题

在 Windows 平台上,当 Python 程序尝试通过 `stdin` 向 C 子进程传递大量二进制数据时,C 的 `fread` 函数可能会提前遇到 EOF(文件结束符),导致数据不完整。这通常是因为 Windows 默认将 `stdin` 设置为文本模式流,并将特定的二进制字节(例如 `\x1A`)解释为文件结束符。为了确保跨平台二进制数据传输的可靠性,需要将 `stdin` 设置为二进制模式。Python 和 C 之间存在二进制数据通信的挑战。

在软件开发中,为了利用不同语言的优势或实现并行计算,我们经常使用 Python 作为协调器来启动并连接已编译的 C 子进程。这种交互通常涉及通过标准输入/输出 (stdin/stdout) 传输数据。对于文本数据,这种通信通常比较直接。然而,当需要传输原始二进制数据时,操作系统之间存在兼容性问题。

一个典型的场景是,一个 Python 程序生成一个大约 1KB 的字节序列,并通过管道将其发送给一个 C 子进程。该程序需要读取这些字节进行处理,并返回一个简短的二进制结果。虽然这种模式在 Linux 上通常运行良好,但在 Windows 上,C 程序在读取部分数据后可能会报告意外的 EOF(文件结束符),导致数据传输失败。根源:Windows 的 I/O 模式差异

这个问题的核心在于 Windows 和 Linux 对标准 I/O 流(如 stdin)的默认处理方式存在差异。Linux 系统:默认情况下,标准 I/O 流以二进制模式运行,数据不会被特殊转换。Windows 系统:默认情况下,标准 I/O 流以文本模式运行。在文本模式下,Windows 会执行“转换”:将 \r\n(回车发行)序列转换为单个 \n(回转行)并读取。更重要的是,它会将 ASCII 码读取为 \x1A(十进制 26),即 Ctrl+Z 字节被视为文件结束符 (EOF)。

当 Python 程序将原始二进制数据写入 C 进程的标准输入时,如果数据意外包含 \x1A 字节,Windows 文本模式的标准输入会将其解释为文件结束符,导致 C 的 fread 或类似函数提前停止读取,并报告 EOF。这就是为什么对于少量数据(因为不包含 \x1A)可能工作正常,但对于大量数据经常失败的原因。子进程在 Python 端被调用。在 Python 端,我们使用 subprocess 模块来创建和管理子进程。为了传输二进制数据,我们需要确保管道以二进制模式打开。Popen 构造函数中的 text=False 参数就是为此目的而设置的。

子进程:import osimport randomfrom subprocess import Popen, PIPE, DEVNULL, STDOUTdef run_cpp_subprocess(data_bytes): quot;quot;quot; 运行 C 子进程,并通过 stdin 传递二进制数据。

command = os.path.join('.','program') # 假设 C 编译的程序名为 'program' # Popen 电影子电影 # stdin=PIPE: 创建一个管道,用于写入程序的 stdin # stderr=PIPE: 捕获进程的错误输出 # text=False: 确保管道以二进制模式打开,而不是文本模式 proc = Popen(command, stdin=PIPE, stderr=PIPE, text=False) # 将分配给引发剧的剧情的 stdin bytes_written = proc.stdin.write(data_bytes) print(f'Python 写入: {bytes_written} 字节') # 关闭 stdin,通知子进程没有更多数据 proc.stdin.close() # 等待子进程完成并获取 stdout 和 stderr stdout_data, stderr_data = proc.communicate() print('\nC stderr:'), stderr_data.decode(errors='ignore'),'\n') print('C stdout:', stdout_data.decode(errors='ignore'),'\n') return stdout_data, stderr_data# 生成一个包含 1000 个随机字节的列表VAR_NUM = 1000vars_list = [random.randint(0, 255) for _ in range(VAR_NUM)] input_bytes = bytes(vars_list) # 转换为 bytes 对象 print('Python 写入原始字节' (部分):')print(vars_list[:20],'...\n') # 打印 20 个字节作为示例# 运行 C 子电影 run_cpp_subprocess(input_bytes) 复制后登录

在上面的 Python 代码中,text=False 是关键,它确保管道在Python 端以二进制模式运行。然而,这无法解决 C 端 stdin 默认文本模式的问题。在 C 语言程序中,通常使用 fread 函数从 stdin 读取数据。如果 stdin 模式没有明确设置,Windows 上的 fread 函数会受到文本模式的影响。

以下是C中电影stdin的最作学院,在Windows上会正解EOF题计:Veed Video Background Remover

Veed推出视频背景去除工具69查看详情#include lt;iostreamgt;#include lt;cstdiogt; // For fread,feof,ferror#include lt;cstdlibgt; // For malloc#define VAR_NUM 1000 // Expected bytes // 模拟从stdin读取字节,存入整数数组。 void read_vars(int* vars) { char buf; int chk; for (int i = 0; i lt; VAR_NUM; i ) { // 每次读一个字节 chk = fread(amp;buf,sizeof(char),1,stdin); // 调试输出,在Windows上会过这些早的EOF // std::cout lt;lt; (int)(unsigned char)buf lt;lt; quot;(quot; lt;lt; chk lt;lt; quot;) quot;; vars[i] = (int)(unsigned char)buf; // 存储读取的字节 if (chk == 0) { // 如果 fread 返回 0,则表示没有读取到字节 if (feof(stdin)) { // 写入 stderr,以便 Python 可以捕获 fwrite(quot;[EOF 检测到过早!]quot;, sizeof(char)), 26, stderr); return; // 提前退出 } if (error(stdin)) { fwrite(quot;[stdin ERROR d

已检测!]quot;,sizeof(char),24,stderr);return;// 提前退出 } } } // std::cout lt;lt;std::endl;// 调试输出 return;}int main() { int* vars = (int*) malloc(VAR_NUM * sizeof(int));if (!vars) { fwrite(quot;[内存分配失败!]quot;,sizeof(char), 26), stderr);return 1;} for (int i = 0;i lt;VAR_NUM;i) vars[i] = 0;// 初始化数组 read_vars(vars);free(vars);// 释放内存 return 0;} 复制后登录

在 Windows 系统上运行上述 C 程序并从 Python 管道接收数据时,C 调试输出会显示 fread 在读取某个字节后突然返回 0,并出现 EOF即使 Python 已经写入了所有预期的字节,仍然检测到了错误。解决方法:在 C 语言中,解决此问题的关键是在 C 程序启动时将 stdin 设置为二进制模式。这可以通过调用 Microsoft C Runtime 来实现。可以使用库提供的 _setmode 函数。_setmode 函数简介

_setmode 函数用于更改指定的文件描述模式(文本或二进制)。_fileno(stdin):获取与文件描述对应的 stdin 流。_O_BINARY:指定要设置为二进制模式的流。

使用此函数包含

修改后的 C 代码

以下是修改后的 C 代码,当主函数启动时,将 stdin 设置为二进制模式: #include lt;iostreamgt;#include lt;cstdiogt; // 用于 fread、feof、ferror#include lt;cstdlibgt; // 用于 malloc、free#include lt;io.hgt; // 用于 _setmode、_fileno#include lt;fcntl.hgt; // 用于 _O_BINARY#include lt;stdexceptgt; // 用于 std::runtime_error(可选,用于更健壮的错误处理)#define VAR_NUM 1000 // 预期字节数 // 模拟从 stdin 读取字节并将其存储在整数数组中 invoid read_vars(int* vars) { char buf; int chk; for (int i = 0; i lt; VAR_NUM; i ) { chk = fread(amp;buf,sizeof(char),1) stdin); vars[i] = (int)(unsigned char)buf; // 存储读取的字节 if (chk == 0) { // 如果 fread 返回 0,则表示没有读取到字节 if (feof(stdin)) { fwrite(quot;[C ERROR:检测到 EOF 过早!]quot;, sizeof(char)), 37, stderr); // 可以在此处抛出异常或采取其他错误处理措施 return; } if (ferror(stdin)) { fwrite(quot;[C ERROR:stdin 流错误!]quot;, sizeof(char), 32, stderr); return; } } } return;}int main() { // 关键步骤:将 stdin 设置为二进制模式 if (_setmode(_fileno(stdin), _O_BINARY) == -1) { fwrite(quot;[C ERROR:无法将 stdin 设置为二进制模式!]quot;,sizeof(char),47,stderr);返回 1;// 设置失败,退出程序} int* vars = (int*)malloc(VAR_NUM * sizeof(int));if (!vars) { fwrite(quot;[C 错误:内存分配失败!]quot

;,sizeof(char),37,stderr);返回 1;} for (int i = 0;i lt;VAR_NUM;i)vars[i] = 0;// 初始化数组 read_vars(vars);free(vars);// 释放内存 return 0;} 复制后登录

通过 main 函数开始 add_setmode(_fileno(stdin)), _O_BINARY), C 程序现在使用二进制模式处理来自 stdin 的数据流,不再将 \x1A 字节解释为 EOF。这样,即使二进制数据包含 \x1A,fread 也可以正确读取所有字节。复制后登录程序

确保编译后的 program.exe 文件与 Python 脚本位于同一目录下,或在命令变量中提供正确的路径。总结与最佳实践

在 Windows 平台上进行 Python 和 C 子进程之间的二进制数据通信时,理解并正确处理标准 I/O 流模式至关重要。首先:在程序开始读取 stdin 之前,使用 `_setmode(_fileno(stdin), _O_BINARY)` 将 stdin 设置为二进制模式。检查错误(feof 和 ferror),并通过 stderr 输出错误信息,以便父​​进程可以捕获和处理。其次:在 Windows 平台上,使用 `_WIN32` 库来包含和调用这些函数,从而保持代码的通用性。

遵循这些实践,可以确保 Python 和 C 子进程之间的二进制数据通信与在 Linux 平台上一样稳定可靠。

以上是解决Windows、Python和C之间二进制数据通信EOF问题的详细内容,请阅读其他相关文章!C/C++环境,扩展对Python文档的支持,写入新行控件

解决Windows上
cell函数是什么意思 cell函数的使用实例
相关内容
发表评论

游客 回复需填写必要信息