Подтвердить что ты не робот

Execv() и константа

Я часто использую функцию execv() в С++, но если некоторые из аргументов находятся в строках С++. Меня раздражает, что я не могу этого сделать:

const char *args[4];

args[0] = "/usr/bin/whatever";
args[1] = filename.c_str();
args[2] = someparameter.c_str();
args[3] = 0;

execv(args[0], args);

Это не скомпилируется, потому что execv() принимает char * const argv [], который несовместим с const char *, поэтому мне нужно скопировать мои std:: строки в символ массивы с использованием strdup(), который является болью.

Кто-нибудь знает причину этого?

4b9b3361

Ответ 1

В базовых спецификациях Open Group объясняется, почему это: для совместимости с существующим C-кодом. Однако ни указатели, ни содержимое строки не должны быть изменены. Таким образом, в этом случае вы можете уйти с const_cast -в результате c_str().

Цитата:

Утверждение о константах argv[] и envp[] включено, чтобы сделать явным для будущих писателей языковых привязок, что эти объекты полностью постоянные. Из-за ограничения стандарта ISO C нельзя утверждать, что идея в стандарте C. Определение двух уровней const - квалификация для параметров argv[] и envp[] для функций exec может показаться естественный выбор, учитывая, что эти функции не изменяют ни массив указателей, ни символы, на которые указывает функция, но это будет запрещать существующий правильный код. Вместо этого только массив указателей отмечен как постоянный.

После этого текст и текст еще более проницательны. Однако Qaru не позволяет вставлять таблицы, поэтому в приведенной выше цитате должно быть достаточно контекста для поиска подходящего места в связанном документе.

Ответ 2

const - это вещь С++ - execv принял аргументы char *, поскольку до того, как существовал С++.

Вы можете использовать const_cast вместо копирования, потому что execv фактически не модифицирует свои аргументы. Возможно, вы захотите написать обертку, чтобы сохранить ввод.

На самом деле, большая проблема с вашим кодом заключается в том, что вы объявили массив символов вместо массива строк.

Try: const char * args [4];

Ответ 3

Я обычно взломал это с помощью:

#define execve xexecve
#include <...>
#include <...>
#include <...>
#undef execve

// in case of c++
extern "C" {
    int execve(const char * filename, char ** argvs, char * const * envp);
}

;/

Ответ 4

Это просто ситуация, когда стиль C/С++ const не работает очень хорошо. На самом деле ядро ​​не собирается изменять аргументы, переданные exec(). Это просто копирует их, когда создает новый процесс. Но система типов недостаточно выразительна, чтобы действительно справляться с этим.

Многие люди на этой странице предлагают сделать exec take "char **" или "const char * const []" . Но ни один из них не работает для вашего оригинального примера. "char **" означает, что все изменено (конечно, не верно для строковой константы "/usr/bin/whatever" ). "const char * const []" означает, что ничего не изменяемо. Но тогда вы не можете назначать какие-либо значения элементам массива, так как сам массив является const.

Лучшее, что вы могли бы сделать, это иметь постоянную C-времени компиляции:

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

Это будет работать с предлагаемой сигнатурой типа "const char * const []" . Но что, если вам нужно переменное количество аргументов? Тогда у вас не может быть константы времени компиляции, но вам нужен изменяемый массив. Итак, ты снова собираешься делать что-то. Это настоящая причина, по которой сигнатура типа exec принимает "const char **" для аргументов.

Кстати, проблемы на С++ одинаковы. Вы не можете передать std::vector < std::string > к функции, которая нуждается в std::vector < const std::string > . Вы должны прибегнуть к типу или скопировать весь std::vector.