从vector< string>转换时,execvp无法正常工作到vector< char *>字符** [英] execvp not working when converting from vector<string> to vector<char*> to char**

查看:107
本文介绍了从vector< string>转换时,execvp无法正常工作到vector< char *>字符**的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

从字符串向量到char *向量到char **时,当参数以char **形式出现时,它正在工作,但是转换似乎有问题,我无法找到差异.

有更好的方法吗?

    vector<string> args;

    /* code that correctly parses args from user input */

    pid_t kidpid = fork();
    if (kidpid < 0)
    {
        perror("Internal error: cannot fork.");
        return -1;
    }
    else if (kidpid == 0)
    {
        // I am the child.

        vector<char*>argcs;
        for(int i=1;i<args.size();i++)
        {
            char * temp = new char[args.at(i).length()];
            for(int k=0;k<args.at(i).length();k++)
            {
                temp[k] = args.at(i).at(k);
            }
            argcs.push_back(temp);
        }

        char** argv = new char*[argcs.size() + 1];
        for (int i = 0; i < argcs.size(); i++)
        {
            argv[i] = argcs[i];
        }
        argv[args.size()] = NULL;

        execvp(program, args);

        return -1;
    }

解决方案

首先,如果下一步要做的是调用execvp,则复制std::string没有任何意义.

如果execvp成功,则它将永远不会返回,并且整个内存映像将消失在烟雾中(或更准确地说,将其替换为全新的映像).在构造新映像的过程中,exec*将argv数组(和环境数组)复制到其中.无论如何,将永远不会调用std::vectorstd::string析构函数.

另一方面,如果execvp失败,则传递给它的参数将不会被修改. (Posix:指针的argv[]envp[]数组以及这些数组所指向的字符串不得通过调用exec函数之一进行修改,除非由于替换了过程映像而导致.")/p>

在任何一种情况下,都不需要复制字符串.您可以使用std::string::c_str()提取指向底层C字符串的指针(作为const char*,但请参见下文).

第二,如果您使用的是C ++ 11或更高版本,则std::vector随便带有data()成员函数,该成员函数返回指向基础存储的指针.因此,如果您有std::vector<char*> svec,则svec.data()将是基础char*[],这就是您要传递到execvp的内容.

因此问题减少到了从std::vector<std::string>创建std::vector<char*>的过程,这很简单:

else if (kidpid == 0) {
    // I am the child.
    std::vector<char*> argc;
    // const_cast is needed because execvp prototype wants an
    // array of char*, not const char*.
    for (auto const& a : args)
        argc.emplace_back(const_cast<char*>(a.c_str()));
    // NULL terminate
    argc.push_back(nullptr);
    // The first argument to execvp should be the same as the
    // first element in argc, but we'll assume the caller knew
    // what they were doing, and that program is a std::string. 
    execvp(program.c_str(), argc.data());
    // It's not clear to me what is returning here, but
    // if it is main(), you should return a small positive value
    // to indicate an error
    return 1;
}

Going from a vector of strings to a vector of char* to a char**, was working when the argument came in as char**, but the conversion seems to have a problem and I'm not able to find the difference.

Is there a better way to do this?

    vector<string> args;

    /* code that correctly parses args from user input */

    pid_t kidpid = fork();
    if (kidpid < 0)
    {
        perror("Internal error: cannot fork.");
        return -1;
    }
    else if (kidpid == 0)
    {
        // I am the child.

        vector<char*>argcs;
        for(int i=1;i<args.size();i++)
        {
            char * temp = new char[args.at(i).length()];
            for(int k=0;k<args.at(i).length();k++)
            {
                temp[k] = args.at(i).at(k);
            }
            argcs.push_back(temp);
        }

        char** argv = new char*[argcs.size() + 1];
        for (int i = 0; i < argcs.size(); i++)
        {
            argv[i] = argcs[i];
        }
        argv[args.size()] = NULL;

        execvp(program, args);

        return -1;
    }

解决方案

First, there's no point in copying the std::strings if the next thing you are going to do is call execvp.

If the execvp succeeds, then it will never return and the entire memory image will vanish into smoke (or, more accurately, be replaced by a completely new image). In the course of constructing the new image, exec* will copy the argv array (and the environment array) into it. In any event, the std::vector and std::string destructors will never be invoked.

If, on the other hand, the execvp fails, then the argument passed into it will not have been modified. (Posix: "The argv[] and envp[] arrays of pointers and the strings to which those arrays point shall not be modified by a call to one of the exec functions, except as a consequence of replacing the process image.")

In either case, there was no need to copy the character strings. You can use std::string::c_str() to extract a pointer to the underlying C string (as a const char*, but see below).

Second, if you're using C++11 or more recent, std::vector conveniently comes with a data() member function which returns a pointer to the underlying storage. So if you have std::vector<char*> svec, then svec.data() will be the underlying char*[], which is what you want to pass into execvp.

So the problem reduces to creating a std::vector<char*> from a std::vector<std::string>, which is straightforward:

else if (kidpid == 0) {
    // I am the child.
    std::vector<char*> argc;
    // const_cast is needed because execvp prototype wants an
    // array of char*, not const char*.
    for (auto const& a : args)
        argc.emplace_back(const_cast<char*>(a.c_str()));
    // NULL terminate
    argc.push_back(nullptr);
    // The first argument to execvp should be the same as the
    // first element in argc, but we'll assume the caller knew
    // what they were doing, and that program is a std::string. 
    execvp(program.c_str(), argc.data());
    // It's not clear to me what is returning here, but
    // if it is main(), you should return a small positive value
    // to indicate an error
    return 1;
}

这篇关于从vector&lt; string&gt;转换时,execvp无法正常工作到vector&lt; char *&gt;字符**的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆