Best practice using execvp in C ++

In the beginning I wrote something like this

char* argv[] = { "ls", "-al", ..., (char*)NULL };
execvp("ls", argv);

However, GCC detected this warning: "C ++ forbids converting a string constant to char*."

Then I changed the code to

const char* argv[] = { "ls", "-al", ..., (char*)NULL };
execvp("ls", argv);

As a result, GCC discovered this error: "Invalid conversion from const char**to char* const*."

Then I changed the code to

const char* argv[] = { "ls", "-al", ..., (char*)NULL };
execvp("ls", (char* const*)argv);

It finally works and compiled without any warnings and errors, but I think it is a little cumbersome and I cannot find anyone to write something like this on the Internet.

Is there a better way to use execvpin C ++?

+4
source share
3 answers

You are in a real problem because you are facing two incompatible limitations:

  • ++, , const char*:

    C char[] ( const) char*. ++ 03 ( , const ++). ++ 11 .

  • C, ( const) char*:

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

    , - cast, execvp.

++. , , , ++ 11 ( nullptr ).

#include <cassert>
#include <unistd.h>

template <std::size_t N>
int execvp(const char* file, const char* const (&argv)[N])
{
  assert((N > 0) && (argv[N - 1] == nullptr));

  return execvp(file, const_cast<char* const*>(argv));
}

int main()
{
  const char* const argv[] = {"-al", nullptr};
  execvp("ls", argv);
}

:

g++ -std=c++11 demo.cpp 

CPP std::experimental::to_array.

+3

execvp() ( , , ) ++- char.

, - , :

#include <unistd.h>
#include <cstring>
#include <memory>
int execvp(const char *file, const char *const argv[])
{
    std::size_t argc = 0;
    std::size_t len = 0;

    /* measure the inputs */
    for (auto *p = argv;  *p;  ++p) {
        ++argc;
        len += std::strlen(*p) + 1;
    }
    /* allocate copies */
    auto const arg_string = std::make_unique<char[]>(len);
    auto const args = std::make_unique<char*[]>(argc+1);
    /* copy the inputs */
    len = 0;                    // re-use for position in arg_string
    for (auto i = 0u;  i < argc;  ++i) {
        len += std::strlen(args[i] = std::strcpy(&arg_string[len], argv[i]))
            + 1; /* advance to one AFTER the nul */
    }
    args[argc] = nullptr;
    return execvp(file, args.get());
}

( std::unique_ptr , , execvp() , ).

:

int main()
{
    const char *argv[] = { "printf", "%s\n", "one", "two", "three", nullptr };
    return execvp("printf", argv);
}
one
two
three
+2

execvperequires char *const argv[]as a second argument. That is, this requires a list of constant pointers to non-constant data. String literals in C are const, so the problem with warnings and dropping yours argvin char* const*is to hack, as it is execvpnow allowed to write strings in argv. The solution I see is to either allocate a buffer for each element, or use instead execlp, which works with arguments const char*and allows you to pass string literals.

0
source

Source: https://habr.com/ru/post/1688567/


All Articles