簡體   English   中英

在 C++ 中使用 execvp 的最佳實踐

[英]Best practice to use execvp in C++

一開始,我寫了這樣的東西

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

您遇到了一個真正的問題,因為我們面臨兩個不兼容的約束:

  1. 來自 C++ 標准的一項要求您必須使用const char*

    在 C 中,字符串文字是char[]類型,可以直接分配給(非常量) char* C++03 也允許它(但不推薦使用它,因為文字在 C++ 中是 const)。 C++11 不再允許這種沒有強制轉換的賦值。

  2. 另一個來自傳統 C 函數原型,它需要一個(非常量) char*數組:

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

因此,某處必須有一個const_cast<>並且我找到的唯一解決方案是包裝execvp函數。

這是此解決方案的完整運行 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 

您可以在std::experimental::to_arrayCPP 參考示例中看到類似的方法。

這是execvp()聲明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

execvpe需要一個char *const argv[]作為它的第二個參數。 也就是說,它需要一個指向非常量數據的常量指針列表。 C 中的字符串文字是 const 因此出現警告問題並將您的argvchar* const*是一個黑客,因為現在允許execvp寫入您的argv的字符串。 我看到的解決方案是為每個項目分配一個可寫緩沖區,或者只使用execlp代替它與const char* args 一起使用並允許傳遞字符串文字。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM