Вызовите программу переменного тока из C++ и передайте аргументы

У меня есть программа на C++, и в какой-то момент в моей программе мне нужно вызвать программу ac и передать ей некоторые аргументы.

Я работаю в Linux Env.

файл simpsh - это скомпилированный c-файл в том же каталоге. result_simpsh_command - это строка с данными этого типа --creat --trunc --wronly f1 и так далее.

Когда я проверяю значения, которые я получаю в программе C, это показывает это вместо

void execute_simpsh(string resulting_simpsh_command)
{
    pid_t pid = fork();

    if(pid == -1)
        perror("Fork failed!");
    else if(pid ==0)
    {
        char* args[256];

        string simpsh ="./simpsh";
        args [0] = (char*) simpsh.c_str();
        string temp_option_holder="";

        int nextCommand=1;

        for(int i=0;i<resulting_simpsh_command.length();i++)
        {
            if(resulting_simpsh_command[i] !=' ')
            {
                temp_option_holder += resulting_simpsh_command[i];
            }
            else
            {
                cout<<"saving to argument: "<<temp_option_holder<<endl;
                args [nextCommand] = (char*) temp_option_holder.c_str();
                temp_option_holder="";
                nextCommand +=1;
            }

        }


        cout<<"command numbers "<<nextCommand<<endl;
        args [nextCommand + 1] = NULL;

        if(execvp(args[0],args) == -1)
            cout<<"Failed to open simpsh, maybe you didnt compile?"<<endl;
        exit(1);
    }
    else
    {
        //not important for now

    }
}

2 ответа

С ++ имеет так много приятных вещей за пределами std::cout, Используй их!

Суть этого решения std::replace()пробелы в командной строке с нулевыми байтами, затем указатели на начало каждой (C) строки в командной строке (удобно использовать нулевые байты из replace() как терминаторы), поместив эти указатели в вектор, мы затем перейдем к execve(),

#include <string>
#include <vector>
#include <algorithm>
#include <iostream>

// Usually I would recommend using const std::string &
// to avoid the copy, but we are going to do violence
// on the argument so we really *want* a writeable copy.
void execute_simpsh( string cmd )
{
    pid_t pid = fork();

    if ( pid == -1 )
    {
        perror("Fork failed!");
    }
    else if ( pid == 0 )
    {
        // This will hold our pointers -- and is not limited
        // to a maximum amount other than available RAM
        std::vector< char * > args( { "./simpsh" } );

        if ( ! cmd.empty() )
        {
            // Tokenize -- std::string may contain null chars!
            std::replace( cmd.begin(), cmd.end(), ' ', '\0' );

            // std::string is zero-terminated in memory, but that
            // zero char is not considered by .find() so we add one,
            // making the loop below easier.
            cmd.append( '\0' );

            size_t i = 0;

            // Gather pointers to each argument. find_first_not_of()
            // skips leading (and embedded) ex-spaces.
            while ( ( i = cmd.find_first_not_of( '\0', i ) ) != std::string::npos )
            {
                args.push_back( cmd.data() + i );
                // find() skips to the end of the current argument.
                i = cmd.find( '\0', i );
            }
        }

        std::cout << "Tokens: " << args.size() << "\n";

        // args.data() is std::vector's underlying array
        // of the pointers we pushed. How convenient...
        for ( auto token : args.data() )
        {
            std::cout << "  " << token << "\n";
        }

        // ...as "array of char *" is exactly what we need.
        if ( execvp( args[0], args.data() ) == -1 )
        {
            std::cout << "Failed to open simpsh" << std::endl;
        }

        std::exit( 1 );
    }
    else
    {
        // ...
    }
}

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

Много args массив будет недействительными указателями из-за вашего (неправильного) использования c_str,
Указатель становится недействительным, как только буфер строки будет перераспределен.
Некоторые из args указатели также могут указывать на одно и то же, даже если они действительны.

Два варианта для исправления этого (от макушки головы):

Динамическое распределение:

args[nextCommand] = strdup(temp_option_holder.c_str());

который требует освобождения позже.

Или, если вы можете жить с ограничением длины аргумента, вы можете использовать другой массив и избежать управления памятью (но тогда вам нужно беспокоиться о переполнениях):

char arg_strings[256][ARGUMENT_LENGTH] = {0};
char* args[256] = {0};

// ...
assert(temp_option_holder.length() < ARGUMENT_LENGTH);
strncpy(arg_strings[nextCommand], temp_option_holder.c_str(), ARGUMENT_LENGTH);
args[nextCommand] = arg_strings[nextCommand];
Другие вопросы по тегам