Can I pass a const char* array to execv?

旧街凉风 提交于 2019-12-07 04:56:10

问题


This is the prototype for execv:

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

Can I pass an array of const char pointers as the second argument?

This example program gives a warning when USE_CAST is not set:

#include <unistd.h>
int main(int argc, char *argv[])
{
    if (argc > 0) {
        const char *exe_name = "/bin/echo", *message = "You ran";
        const char *exe_args[] = { exe_name, message, argv[0], NULL };
#ifdef USE_CAST
    execv("/bin/echo", (char **) exe_args);
#else
    execv("/bin/echo", exe_args);
#endif
    }
    return 0;
}

When compiling, gcc says, "passing argument 2 of 'execv' from incompatible pointer type" if I don't use the cast.

From the POSIX documentation for execv (halfway through the Rationale section), it looks like the second argument is a char *const array only for backwards compatibility:

The statement about argv[] and envp[] being constants is included to make explicit to future writers of language bindings that these objects are completely constant. ... It is unfortunate that the fourth column cannot be used...

where the "fourth column" refers to const char* const[].

Is the (char **) cast safe to use here? Should I create a char * array and pass that to execv instead?


回答1:


Can I pass an array of const char pointers as the second argument?

Well yes, you already know that you can cast in order to do so.

From the POSIX documentation for execv (halfway through the Rationale section), it looks like the second argument is a char *const array only for backwards compatibility:

I wouldn't put it in those terms, but yes, there is a compatibility aspect to the chosen signature. The section you reference explains that C does not have a wholly satisfactory way to express the degree of const-ness that POSIX requires execv() to provide for the arguments. POSIX guarantees that the function will not change either the pointers in argv or the strings to which they point.

With that being the case, I think it not unreasonable to cast the argv pointer as you propose to do, though I would leave a comment in my code explaining why doing so is safe.

On the other hand, you should consider simply leaving the const off of your array declaration:

char *exe_name = "echo", *message = "You ran";
char *exe_args[] = { exe_name, message, argv[0], NULL };

Or, in your simple example, even this would do:

char *exe_args[] = { "echo", message, argv[0], "You ran", NULL };

C string literals correspond to arrays of type char, not const char, so this is perfectly legal as far as C is concerned, even though actually trying to modify the contents of those strings might fail.

On the third hand, modern C has array literals, so you could even do this:

execv("/bin/echo", (char *[]) { "echo", "You ran ", argv[0], NULL });

In that last case you don't even have a cast (the thing that resembles one is just part of the syntax for an array literal).




回答2:


If you're just going to cast away the const, then you shouldn't use const to begin with. Most (dare I say all) compilers will accept the following code

char *exe_name = "/bin/echo";
char *message = "You ran";
char *exe_args[] = { exe_name, message, argv[0], NULL };
execv( exe_args[0], exe_args );

If that is not pedantically correct enough for you, then the other option is

char exe_name[] = "/bin/echo";
char message[] = "You ran";
char *exe_args[] = { exe_name, message, argv[0], NULL };
execv( exe_args[0], exe_args );

Note that execv is going to make copies of the strings (to create the argv array for the executable), so it doesn't matter whether the strings are actually const or not.



来源:https://stackoverflow.com/questions/36925388/can-i-pass-a-const-char-array-to-execv

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!