Вызовите программу переменного тока из 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];