在C ++中使用execvp的最佳实践

时间:2017-11-02 06:28:56

标签: c++ execvp

一开始,我写了类似的东西

char* argv[] = { "ls", "-al", ..., (char*)NULL };
execvp("ls", argv);

然而,GCC弹出了警告," C ++禁止将字符串常量转换为char*。"

然后,我将代码更改为

const char* argv[] = { "ls", "-al", ..., (char*)NULL };
execvp("ls", argv);

结果,GCC弹出了错误,"从const char**char* const*的转换无效。"

然后,我将代码更改为

const char* argv[] = { "ls", "-al", ..., (char*)NULL };
execvp("ls", (char* const*)argv);

它最终运行并且编译时没有任何警告和错误,但我认为这有点麻烦,我找不到有人在互联网上写过这样的东西。

有没有更好的方法在C ++中使用execvp

3 个答案:

答案 0 :(得分:5)

你遇到了一个真正的问题,因为我们面临两个不兼容的约束:

  1. C ++标准中的一个要求您必须使用const char*

      

    在C中,字符串文字的类型为char[],可以直接分配   到(非常)char*。 C ++ 03也允许它(但不赞成使用它,   因为文字是C ++中的const)。 C ++ 11不再允许这样的分配   没有演员。

  2. 另一个来自遗留C函数原型,需要一个(非常量)char*数组:

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

    因此,某处必须有强制转换,我找到的唯一解决方案是包装execvp函数。

  3. 这是该解决方案的完整运行C ++演示。不方便的是你有一些胶水代码可以写一次,但优点是你得到更安全,更清洁的C ++ 11 代码(最后nullptr被检查)。

    #include <cassert>
    #include <unistd.h>
    
    template <std::size_t N>
    int execvp(const char* file, const char* const (&argv)[N])
    {
      assert((N > 0) && (argv[N - 1] == nullptr));
    
      return execvp(file, const_cast<char* const*>(argv));
    }
    
    int main()
    {
      const char* const argv[] = {"-al", nullptr};
      execvp("ls", argv);
    }
    

    您可以使用以下代码编译此演示:

    g++ -std=c++11 demo.cpp 
    

    您可以在CPP Reference example for std::experimental::to_array中看到类似的方法。

答案 1 :(得分:2)

这是execvp()的声明(它不能修改其参数,为了向后兼容)和字符串文字的C ++解释为常量char的数组之间的冲突。

如果演员关注你,你剩下的选择是复制参数列表,如下所示:

#include <unistd.h>
#include <cstring>
#include <memory>
int execvp(const char *file, const char *const argv[])
{
    std::size_t argc = 0;
    std::size_t len = 0;

    /* measure the inputs */
    for (auto *p = argv;  *p;  ++p) {
        ++argc;
        len += std::strlen(*p) + 1;
    }
    /* allocate copies */
    auto const arg_string = std::make_unique<char[]>(len);
    auto const args = std::make_unique<char*[]>(argc+1);
    /* copy the inputs */
    len = 0;                    // re-use for position in arg_string
    for (auto i = 0u;  i < argc;  ++i) {
        len += std::strlen(args[i] = std::strcpy(&arg_string[len], argv[i]))
            + 1; /* advance to one AFTER the nul */
    }
    args[argc] = nullptr;
    return execvp(file, args.get());
}

(您可能会认为std::unique_ptr有点矫枉过正,但如果execvp()失败,此函数正确清理,并且函数会返回。)

演示:

int main()
{
    const char *argv[] = { "printf", "%s\n", "one", "two", "three", nullptr };
    return execvp("printf", argv);
}
one
two
three

答案 2 :(得分:0)

execvpe需要char *const argv[]作为第二个参数。也就是说,它需要一个指向非const数据的const指针列表。 C中的字符串文字是const,因此警告问题并将argv强制转换为char* const*是一种黑客攻击,因为execvp现在可以写入argv中的字符串。我看到的解决方案是为每个项目分配一个可写缓冲区,或者只使用execlp代替const char* args并允许传递字符串文字。