You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言使用fork-execv调用Python文件内函数报错如何解决

C程序通过fork+execv调用Python脚本指定函数的参数配置问题

背景说明

我想在C程序中通过fork和execv创建子进程调用Python脚本,最初测试调用/bin/ls可正常运行,测试代码如下:

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
    int status;
    char *args[2];

    args[0] = "/bin/ls"; 
    args[1] = NULL; 

    if ( fork() == 0 ){
        printf("I am the child\n");
        execv( args[0], args ); }
    else {
        printf("I am the parent\n");
        wait( &status ); }

    return 0;
}

目标Python脚本

后续需要调用如下Python文件中的Create_Buffer()函数,Python脚本路径为/opt/P01_SH/NLTK_Gutenberg/NLTK_Python_Libs.py,内容如下:

#!/usr/bin/python3

from nltk.corpus import gutenberg

def Create_Buffer():

    out_buf = []
    pointer = id(out_buf)

    value_in = 21

    print("I was here")
    print(value_in)

    return pointer

def NLTK_Python_Libs(n):

    if n == 0:
        n = n + 1
        return id(n)

错误尝试与报错

第一次修改后报错

我最初将C代码修改为如下内容:

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
    int status;
    char * paramsList[] = { "/bin/bash", "-c", "/usr/bin/python",   "/opt/P01_SH/NLTK_Gutenberg/NLTK_Python_Libs.Create_Buffer()", (char *)NULL };

    if ( fork() == 0 ){
        printf("I am the child\n");
        execv("/usr/bin/python",paramsList); }
    else {
        printf("I am the parent\n");
        wait( &status ); }

    return 0;
}

运行后出现语法错误:

I am the parent
I am the child
File "string", line 1
/usr/bin/python
SyntaxError: invalid syntax

第二次修改后报错

微调代码后内容如下:

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
    int status;
    char *args[5];
    args[0] = "/bin/bash";
    args[1] = "-c";
    args[2] = "/usr/bin/python";
    args[3] =   "/opt/P01_SH/NLTK_Gutenberg/NLTK_Python_Libs.Create_Buffer()"; 
    args[4] = NULL;

    if ( fork() == 0 ){
        printf("I am the child\n");
        execv(args[0], args); }
    else {
        printf("I am the parent\n");
        wait( &status ); }

    return 0;
}

这次运行后直接进入Python交互式命令行,没有执行目标函数:

I am the parent
I am the child
Python 3.8.0 (default, Feb 25 2021, 22:10:10)
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

我尝试修改Python脚本的shebang行,替换为#!/usr/bin/python、#!/usr/bin/python3、#!/usr/bin/env python3或是直接删除,都没有解决问题。

需求说明

我需要在符合以下要求的前提下,实现C程序调用Python文件内的指定函数,支持传参:

  • 可以使用任意exec系列函数,但必须使用绝对路径,禁止使用名称中带“p”的exec类函数
  • 按名称调用指定函数,不能仅执行完整Python文件
    C程序编译指令为:
gcc -fPIC -ggdb -o NLTK_Python.exe NLTK_Python.c -Wall -Wextra

运行环境为Ubuntu 18.04、Python 3.8。


解决方案

错误原因分析

你之前两次修改的代码都存在参数构造错误:

  1. 第一次错误:你给execv传入的第一个参数是/usr/bin/python,但参数数组第一个元素是/bin/bash,参数列表和执行的程序不匹配,Python会把后续的/bin/bash等内容当成要执行的Python代码,自然报语法错误。
  2. 第二次错误:bash -c后面的完整命令需要拼接成单个字符串,不能拆分。你把/usr/bin/python和后面的函数调用拆成了两个参数,bash只会把/usr/bin/python当成要执行的命令,后面的路径会被当成Python的位置参数,相当于直接执行python,所以进入了交互式界面。

正确实现方式

要调用指定Python文件中的函数,可以利用Python的-c参数执行一段导入模块+调用函数的代码片段,两种实现方案如下:

方案1:直接调用python,不经过bash

不需要额外调用bash,直接构造符合Python参数规则的数组即可,代码如下:

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
    int status;
    // 构造Python参数:参数0是python本身,参数1是-c,参数2是要执行的Python代码串,最后以NULL结尾
    char *args[] = {
        "/usr/bin/python3",
        "-c",
        "import sys; sys.path.insert(0, '/opt/P01_SH/NLTK_Gutenberg'); from NLTK_Python_Libs import Create_Buffer; Create_Buffer()",
        NULL
    };

    if (fork() == 0) {
        printf("I am the child\n");
        execv(args[0], args);
        // execv执行成功不会返回,走到这里说明执行失败
        perror("execv failed");
        _exit(1);
    } else {
        printf("I am the parent\n");
        wait(&status);
    }

    return 0;
}

如果需要给函数传参,可以直接在代码串里拼接参数,或者通过sys.argv获取:
比如要给Create_Buffer传整数参数100,可以把参数数组改成:

char *args[] = {
    "/usr/bin/python3",
    "-c",
    "import sys; sys.path.insert(0, '/opt/P01_SH/NLTK_Gutenberg'); from NLTK_Python_Libs import Create_Buffer; Create_Buffer(int(sys.argv[1]))",
    "100",
    NULL
};

方案2:经过bash调用

如果需要通过bash执行,要把完整的Python调用命令拼接成单个字符串传给bash -c:

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
    int status;
    char *args[] = {
        "/bin/bash",
        "-c",
        "/usr/bin/python3 -c 'import sys; sys.path.insert(0, \"/opt/P01_SH/NLTK_Gutenberg\"); from NLTK_Python_Libs import Create_Buffer; Create_Buffer()'",
        NULL
    };

    if (fork() == 0) {
        printf("I am the child\n");
        execv(args[0], args);
        perror("execv failed");
        _exit(1);
    } else {
        printf("I am the parent\n");
        wait(&status);
    }

    return 0;
}

注意事项

  1. 必须先把Python脚本所在的目录加入sys.path,否则Python无法找到对应的模块导入
  2. exec系列函数执行成功后不会返回,所以建议在execv后面加错误打印和退出逻辑,方便排查问题
  3. 所有路径都使用绝对路径,符合要求,没有用到带p的exec函数

内容的提问来源于stack exchange,提问作者RTC222

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 15:57:00