Как передать вектор строк в execv - PullRequest
3 голосов
/ 27 апреля 2011

Я обнаружил, что самый простой способ построить список аргументов моей программы - это вектор строк.Однако execv ожидает массив символов для второго аргумента.Какой самый простой способ заставить его принять вектор строк?

Ответы [ 5 ]

13 голосов
/ 27 апреля 2011

execv() принимает только массив строковых указателей.Нет способа заставить его принять что-либо еще.Это стандартный интерфейс, который можно вызывать из любого языка размещения, а не только из C ++.

Я протестировал компиляцию этого:

    std::vector<string> vector;
    const char *programname = "abc";

    const char **argv = new const char* [vector.size()+2];   // extra room for program name and sentinel
    argv [0] = programname;         // by convention, argv[0] is program name
    for (int j = 0;  j < vector.size()+1;  ++j)     // copy args
            argv [j+1] = vector[j] .c_str();

    argv [vector.size()+1] = NULL;  // end of arguments sentinel is NULL

    execv (programname, (char **)argv);
2 голосов
/ 27 апреля 2011

Прототип для execv:

int execv(const char *path, char *const argv[]);

Это означает, что список аргументов - это массив указателей на строки c с нулевым символом в конце.

У вас есть vector<string>. Узнайте размер этого вектора и сделайте массив указателей на символ. Затем выполните цикл по вектору и для каждого string в векторе установите соответствующий элемент массива, чтобы он указывал на него.

1 голос
/ 08 декабря 2017

Да, это можно сделать довольно просто, используя преимущества внутреннего массива, который используют векторы. Лучше не использовать строки C ++ в векторе, строковые литералы const_cast и string.c_str () для char *.

Это будет работать, поскольку стандарт гарантирует, что его элементы хранятся непрерывно (см. https://stackoverflow.com/a/2923290/383983)

#include <vector>

using std::vector;

int main() {
  vector<char*> commandVector;

  // do a push_back for the command, then each of the arguments
  commandVector.push_back(const_cast<char*>("echo"));
  commandVector.push_back(const_cast<char*>("testing"));
  commandVector.push_back(const_cast<char*>("1"));
  commandVector.push_back(const_cast<char*>("2"));
  commandVector.push_back(const_cast<char*>("3"));

  // push NULL to the end of the vector (execvp expects NULL as last element)
  commandVector.push_back(NULL);

  const int status = execvp(command[0], &command[0]);
  return 0;
}

Сделайте const_cast, чтобы избежать "устаревшего преобразования из строковой константы в 'char *'". Строковые литералы реализованы как «const char *» в C ++. const_cast - это самая безопасная форма приведения здесь, поскольку она только удаляет const и не занимается другими забавными делами. execvp не будет редактировать значения в любом случае.

Если вы хотите избежать всех приведений, вам нужно усложнить этот код, скопировав все значения в типы 'char *', которые не стоят того.

Хотя, если число аргументов, которые вы хотите передать execv / execl, известно, это легче написать в C.

1 голос
/ 27 апреля 2011

Я наткнулся на ту же проблему некоторое время назад.

Я закончил построение списка аргументов в std::basic_string<char const*>.Затем я вызвал метод c_str() и сделал const_cast<char* const*> для результата, чтобы получить список в формате, который execv принимает.

Для составных аргументов я new ed строки (обычные строки, сделанныеобычных символов;)), взяли их c_str() и дали им утечку.

const_cast необходимо удалить дополнительно const, так как метод c_str() данного типа строки возвращает char const* const* ирк.Печатая это, я думаю, что мог бы использовать std::basic_string<char*>, но я думаю, у меня была причина ...


Я хорошо знаю, что const -кастинг и утечка памяти выглядят немного грубыми иэто действительно плохая практика, но поскольку execv заменяет весь процесс, это все равно не имеет значения.

1 голос
/ 27 апреля 2011

Вы не можете изменить работу execv (в любом случае это не так просто), но вы можете перегрузить имя функции тем, которое работает так, как вы хотите:

int execv(const string& path, const vector<string>& argv) {
    vector<const char*> av;
    for (const string& a : argv) {
        av.push_back(a.c_str());
    av.push_back(0);
    return execv(path.c_str(), &av[0]);
}

Конечно, это может вызвать некоторую путаницу. Вам лучше дать ему имя, отличное от execv ().

NB: Я просто набрал это на макушке. Это может не сработать. Может даже не скомпилироваться; -)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...