Linux下C语言中调用其他程序的办法

来源:互联网 发布:网络市场推广方案 编辑:程序博客网 时间:2024/06/04 08:14

1.问题场景

在一些项目中,或许会有多种编程语言同时存在。有些功能采用脚本实现,如Shell或者python,主程序只需要调用相应的脚本即可。

下面将具体阐述如何进行调用。

2.解决办法

我们知道,fork()可以新建一个子进程,在子进程里通过exec函数就可以进行新的程序执行了。这个框架刚好适合我们的问题。

exec函数有很多种,如下:

int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);
path和file指代欲执行的脚本文件,arg和argv指代传入的参数。
6个函数,还有不同的参数列表,是不是容易混乱?这样记忆事半功倍:v代表vector(矢量,向量),l代表list(清单),.具体来说,有v的函数,在向脚本传递参数的时候才用的是argv[]数组,数组的最后一个元素为NULL表示结尾;与v互斥的是l,有l的函数,向脚本传递参数的时候是顺序写在函数中的,以NULL结束。含有e的函数,第一个参数为应用程序所在的完整路径,含有p的函数,参数为应用程序名称即可,函数会自行去某些目录下去寻找。

3.应用实例

假设有一个python脚本test_touch.py,功能是新建一个文件,文件名由传入的参数决定。如下:

import osimport sysos.popen("touch %s" % argv[1])sys.exit(0)

采用fork+exec,写一个c语言程序调用它。

#include <unitstd.h>#include<sys/wait.h>int main(){    pid_t pid;    int istatus;    int ret;    char *params[3];    params[0] = "test_touch.py";    params[1] = "new_file";    params[2] = NULL;     pid = fork();       if(0 > pid)    {        printf("fork error!\n");        exit(-1);    }    if(0 == pid)    //子进程执行文件    {        execvp("test_touch.py",params);        printf("execvp error!\n");        exit(-1);    }    else if(0 < pid)   //父进程获取脚本返回值    {        waitpid(pid,&istatus,NULL);  //等待子进程结束,并将返回值放入istatus        if(WIFEXITED(istatus))        {             ret = WEXITSTATUS(istatus);             printf("The return code of the script is %d", ret);        }    }    return 0;}

上述程序中采用的是execvp函数,如2中所述,execvp第一个参数是待执行的文件名字,而具体位置会由程序在执行过程中从“某些目录”中寻找,这些目录就是环境变量。

而如果我们的执行文件并没有存放在环境变量下,就会执行失败。那么怎么看我们的执行文件是否在环境变量下呢?

在终端中执行echo $PATH,可以得到一系列目录,由冒号隔开,这些目录就构成了环境变量。可以把文件放在其中一个目录下,也可以将文件所在目录加入环境变量。

如果觉得这样太过繁琐,可以直接用其他exec函数,如

 execl(“/root/test_touch.py”, "new_file", NULL);        //假设test_touch.py存放在root目录下

此外,当execvp文件执行成功,子进程会自动退出,不会接着执行下面的语句。只有在执行失败的时候,会返回-1,并接着执行。

      printf("execvp error!\n");      exit(-1);

4.探讨

有时候我们希望执行脚本文件并获得一些返回值。上述c语言代码中我们可以看到通过waitpid,我们可以得到文件sys.exit(0)返回的值,因此,可以将有用的整数通过sys.exit返回,在c文件中进行读取。然而,这限制了返回值必须只有一个,而且需要是整数。

那么当我们需要查看更多返回值的时候该怎么办呢?

这里提出一个解决方案,在脚本文件中新建一个文件,将感兴趣的值写入这个文件。然后在c语言中读取该文件,从而达到信息反馈的目的。

如果有其它更加好的办法,欢迎提出讨论。