1

I'm having difficulty figuring out exactly how to use execvp in C++. I'm not having any issues getting my code to work, but I'm specifically trying to figure out how to do it in a way that doesn't make the compiler complain.

I have looked at various questions on Stack Overflow and other resources, but I have been unable to find a solution that results in zero warnings from the compiler.

Consider the following C++ program, which prints its own source code:

#include <unistd.h>

int main(int argc, char *argv[])
{
    char *args[3];
    args[0] = "/bin/cat";
    args[1] = __FILE__;
    args[2] = NULL;

    execvp(args[0], args);

    return 0;
}

(I know that the return 0 should never be reached; I'm not so concerned with error handling in this question.)

When I compile it, the compiler emits two warnings:

 $ g++ -Wall exec.cpp
exec.cpp: In function ‘int main(int, char**)’:
exec.cpp:6:15: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]
     args[0] = "/bin/cat";
               ^~~~~~~~~~
exec.cpp:7:15: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]
     args[1] = __FILE__;
               ^~~~~~~~

The compiled program successfully prints the source file. However, I'd really like to get the program to compile without any warnings. Since the compiler doesn't like that the string literals are being assigned to a pointer of type char* (not const char*), I suppose it would make sense to mark args as an array of const char* pointers. Consider this version of the program:

#include <unistd.h>

int main(int argc, char *argv[])
{
    const char *args[3];
    args[0] = "/bin/cat";
    args[1] = __FILE__;
    args[2] = NULL;

    execvp(args[0], args);

    return 0;
}

I would think that this program should compile and run with no warnings or errors, but the compiler does emit an error:

 $ g++ -Wall exec.cpp
exec.cpp: In function ‘int main(int, char**)’:
exec.cpp:10:25: error: invalid conversion from ‘const char**’ to ‘char* const*’ [-fpermissive]
     execvp(args[0], args);
                         ^
In file included from exec.cpp:1:0:
/usr/include/unistd.h:581:12: note:   initializing argument 2 of ‘int execvp(const char*, char* const*)’
 extern int execvp (const char *__file, char *const __argv[])
            ^~~~~~

I also tried declaring args as char const *args[3], but the compiler emits the same error. The only way I am able to get it to compile with no warnings is by casting args in the call to execvp:

const char *args[3];
...
execvp(args[0], (char* const*)args);

This version compiles without warnings and runs successfully. However, I prefer to avoid casting when I can, because it makes it harder for me to reason about the type conversions going on.

Are one of the two working ways that I have shown above the best way to create an argument array to pass to execvp, or is there a better way that is clear and does not result in the compiler complaining?

I am using two different compilers - g++ 6.2.0 for native compilation on Ubuntu x86_64, and g++ 4.5.3 for cross compilation to an ARM platform.

Edit:

I do not believe that my question is a duplicate of this question. I understand the different effects of using const in different ways with respect to a char* variable. I am specifically asking which type is conventionally used for execvp calls, which is not answered by the linked question.

millinon
  • 1,528
  • 1
  • 20
  • 31
  • How about `auto args[3] = { "/bin/cat", __FILE__, nullptr };` ? – Jesper Juhl Jul 06 '17 at 16:20
  • g++ doesn't like that either: `error: ‘args’ declared as array of ‘auto’`. I'm not very familiar with the auto keyword - would that require that a C++ standard be specified to g++? – millinon Jul 06 '17 at 16:24
  • C++11 minimum (`-std=c++11` or `-std=c++14`). – Jesper Juhl Jul 06 '17 at 16:26
  • My cross-compiler unfortunately does not recognize either of those flags (I'm stuck with an ancient compiler). The native g++ does recognize them, but with both `-std=c++11` and `-std=c++14`, but strangely still emits the same error about an array of `auto`s. Also, it's more important that I figure out something that works with the cross-compiler, so it wouldn't be a solution even if it did work with the native compiler. – millinon Jul 06 '17 at 16:32

0 Answers0