问题
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[]
andenvp[]
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