0

I want to pass an array of arguments to exec() function. The current parameters are all strings. How could I convert the array of string into the array of char array?

Right now I'm using const_cast to remove the const. The code does not look nice. Is there a better solution?

Sample code looks like:

void f(const string &dev, const string &status){

  char* args[] = {"link", "set", "dev", const_cast<char*>(dev.c_str()), 
  const_cast<char*>(status.c_str())};
  execv("/sbin/ip", args);
}
4
  • Why don't you add const in the type iso casting it away? Commented May 22, 2019 at 21:18
  • 1
    char* arg0 = "link" should also be problematic, as const (or cast here) is missing too... Commented May 22, 2019 at 21:22
  • I am not sure, but will the lifetimes of dev and status matter here? You're calling execv and populating it with strings returned by std::string's that go out of scope after main exits. Commented May 22, 2019 at 21:26
  • Can you take parameter by value, instead of const ref? (a way to remove const, and if copy would have be done in function (as suggested in answer, it might avoid an extra copy)). Commented May 22, 2019 at 21:37

2 Answers 2

1

It's probably best to declare args as an array of char const*:

char const* args[] = {"link", "set", "dev", dev.c_str(), status.c_str()};

However, if you truly need a char* and not a char const*, as execv requires, we need std::string::data:

void f(const string &dev_, const string &status_){
  // Note: string literals don't convert to char* in C++,
  // although some compilers allow it as an extension.

  // Declare these as arrays so we can form `char*`s to them:
  char link[] = "link";
  char set[] = "set";
  char dev_lit[] = "dev";

  // No choice but to copy the const args:
  std::string dev{dev_};
  std::string status{status_};

  // C++17-specific:
  char* args[] = {link, set, dev_lit, dev.data(), status.data()};
  execv("/sbin/ip", args);
}

Before C++17, you can use &status[0] rather than status.data(), which is correct even if status.size() == 0.

Sign up to request clarification or add additional context in comments.

4 Comments

The issue with this approach is that execv is taking char *const. If I'm passing char const*, it will throw error invalid conversion from ‘const char**’ to ‘char* const*’.
@stcheng Yeah, that's why I also gave how to get char*s instead of char const*s.
just updated my question, the two strings are also const :(
As you copy arguments, taking them by copy might make sense.
0

The code does not look nice. Is there a better solution?

For what it's worth, use of

char* args[] = {"link", "set", "dev", ... };

is wrong to start with. String literals can decay to char const*, not char*.

I suggest use of a helper function that uses strdup to give you a copy of the input string.

char* toArg(std::string const& s)
{
    return strdup(s.c_str());
}

and use

char* args[] = {toArg("link"), toArg("set"), toArg("dev"), toArg(dev), toArg(status)};

3 Comments

BTW, "link" is still not a char*.
@Jarod42, true.
This is C++, not C. Don't use strdup, use a std::string copy. Besides, heap-allocating memory for the string literals is wasteful.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.