首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在C++中使用带命令行参数的system()

在C++中使用带命令行参数的system()
EN

Stack Overflow用户
提问于 2018-10-21 19:05:55
回答 2查看 158关注 0票数 1

我正在尝试用Linux编写一个程序,其中要执行的命令是作为命令行参数传递的。我写了一段代码,但它有时运行文件,有时不工作,我不知道问题是什么。

下面是我的代码:

代码语言:javascript
复制
#include<stdio.h>
#include<string.h>
#include<unistd.h>

void main(int argc, char* argv[]){

    char com[60];
    int i;

    for(i = 1 ; i < argc ; i++){

        strcat(com, argv[i]);
        strcat(com, " ");
    }

    system(com);
}
EN

回答 2

Stack Overflow用户

发布于 2018-10-21 19:12:13

您的程序具有未定义的行为。

如果用户不传递任何参数,则永远不会进入循环,而您将进入

代码语言:javascript
复制
char com[60];
// ...
system(com);

此时com的内容未初始化,因此对system的调用具有未定义的行为。

如果用户传递参数,则执行此操作

代码语言:javascript
复制
strcat(com, argv[i]);

此时com的内容未初始化,因此对strcat的调用具有未定义的行为。

要解决此问题,请在循环之前将com设置为有效字符串:

代码语言:javascript
复制
char com[60];
com[0] = '\0';
票数 2
EN

Stack Overflow用户

发布于 2018-10-21 19:36:52

这有时会使缓冲区溢出(非常糟糕),有时会出现引用错误,没有参数的情况下,缓冲区将无法初始化(=>未定义行为)。

当shell运行你的程序时,它会去掉字符串的引号并插入$-variables。要健壮地完成此转发,除了检查缓冲区溢出之外,还需要重新报价。对于一个短小的程序来说,这可能有点乏味。

更简单的方法是直接使用argv数组执行posix_spawn或fork/exec:

代码语言:javascript
复制
int status;
pid_t pid;

if (0>(pid=fork())) return -1;
if(0==pid){
    execvp(argv[1],argv+1);
    _exit(127);
}
while(0>(waitpid(pid,&status,0)))
    if (EINTR==errno) continue; else abort(); /*shouldn't happen*/

现在,真正的system()还会忽略父进程中的SIGINT/SIGQUIT,并在获取状态之前阻止父进程中的SIGCHLDposix_spawnp也是首选。

要复制这一点,您可以从musl libc的system实现开始,然后修改它以创建一个

代码语言:javascript
复制
int my_system(char const *file, char *argv[i]);

这将跳过shell (以及创建具有正确引号和缓冲区溢出检查的字符串的需要):

代码语言:javascript
复制
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
#include <spawn.h>
#include <errno.h>
#include <pthread.h>

//extern char **__environ;
extern char **environ;

int my_system(char const *file, char *argv[])
{
    pid_t pid;
    sigset_t old, reset;
    struct sigaction sa = { .sa_handler = SIG_IGN }, oldint, oldquit;
    int status = -1, ret;
    posix_spawnattr_t attr;

    //pthread_testcancel();

    //if (!cmd) return 1;

    sigaction(SIGINT, &sa, &oldint);
    sigaction(SIGQUIT, &sa, &oldquit);
    sigaddset(&sa.sa_mask, SIGCHLD);
    sigprocmask(SIG_BLOCK, &sa.sa_mask, &old);

    sigemptyset(&reset);
    if (oldint.sa_handler != SIG_IGN) sigaddset(&reset, SIGINT);
    if (oldquit.sa_handler != SIG_IGN) sigaddset(&reset, SIGQUIT);
    posix_spawnattr_init(&attr);
    posix_spawnattr_setsigmask(&attr, &old);
    posix_spawnattr_setsigdefault(&attr, &reset);
    posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGDEF|POSIX_SPAWN_SETSIGMASK);

#if 0
    ret = posix_spawn(&pid, "/bin/sh", 0, &attr,
        (char *[]){"sh", "-c", (char *)cmd, 0}, environ);
#else
    ret = posix_spawnp(&pid, file, 0, &attr, argv, environ);
#endif

    posix_spawnattr_destroy(&attr);

    if (!ret) while (waitpid(pid, &status, 0)<0 && errno == EINTR);
    sigaction(SIGINT, &oldint, NULL);
    sigaction(SIGQUIT, &oldquit, NULL);
    sigprocmask(SIG_SETMASK, &old, NULL);

    if (ret) errno = ret;
    return status;
}

现在有了my_system,您就不需要报价了,只需用以下命令调用它

代码语言:javascript
复制
my_system(argv[1], argv+1);
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52914641

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档