[ACCEPTED]-execv() and const-ness-unix

Accepted answer
Score: 37

The Open Group Base Specifications explains 23 why this is: for compatibility with existing 22 C code. Neither the pointers nor the string 21 contents themselves are intended to be changed, though. Thus, in 20 this case, you can get away with const_cast-ing the 19 result of c_str().

Quote:

The statement about argv[] and envp[] being 18 constants is included to make explicit to 17 future writers of language bindings that 16 these objects are completely constant. Due 15 to a limitation of the ISO C standard, it 14 is not possible to state that idea in standard 13 C. Specifying two levels of const- qualification 12 for the argv[] and envp[] parameters for the exec functions 11 may seem to be the natural choice, given 10 that these functions do not modify either 9 the array of pointers or the characters 8 to which the function points, but this would 7 disallow existing correct code. Instead, only 6 the array of pointers is noted as constant.

The 5 table and text after that is even more insightful. However, Stack 4 Overflow doesn't allow tables to be inserted, so 3 the quote above should be enough context 2 for you to search for the right place in 1 the linked document.

Score: 3

const is a C++ thing - execv has taken char 8 * arguments since before C++ existed.

You 7 can use const_cast instead of copying, because 6 execv doesn't actually modify its arguments. You 5 might consider writing a wrapper to save 4 yourself the typing.

Actually, a bigger problem 3 with your code is that you declared an array 2 of characters instead of an array of strings.

Try: const 1 char* args[4];

Score: 1

This is just a situation where C / C++ style 30 const doesn't work very well. In reality, the 29 kernel is not going to modify the arguments 28 passed to exec(). It's just going to copy 27 them when it creates a new process. But 26 the type system is not expressive enough 25 to really deal with this well.

A lot of people 24 on this page are proposing making exec take 23 "char**" or "const char * const[]". But 22 neither of those actually works for your 21 original example. "char**" means that everything 20 is mutable (certainly not not true for the 19 string constant "/usr/bin/whatever"). "const 18 char *const[]" means that nothing is mutable. But 17 then you cannot assign any values to the 16 elements of the array, since the array itself 15 is then const.

The best you could do is have 14 a compile-time C constant like this:

const char * const args[] = {
  "/usr/bin/whatever",
  filename.c_str(),
  someparameter.c_str(),
  0};

This 13 will actually work with the proposed type 12 signature of "const char *const[]". But 11 what if you need a variable number of arguments? Then 10 you can't have a compile-time constant, but 9 you need a mutable array. So you're back 8 to fudging things. That is the real reason 7 why the type signature of exec takes "const 6 char **" for arguments.

The issues are the 5 same in C++, by the way. You can't pass 4 a std::vector < std::string > to a function 3 that needs a std::vector < const std::string 2 >. You have to typecast or copy the entire 1 std::vector.

More Related questions