我可以将 const char* 数组传递给 execv 吗?

Can I pass a const char* array to execv?

这是 execv 的原型:

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

我可以传递一个 const char 指针数组作为第二个参数吗?

此示例程序在未设置 USE_CAST 时发出警告:

#include <unistd.h>
int main(int argc, char *argv[])
{
    if (argc > 0) {
        const char *exe_name = "/bin/echo", *message = "You ran";
        const char *exe_args[] = { exe_name, message, argv[0], NULL };
#ifdef USE_CAST
    execv("/bin/echo", (char **) exe_args);
#else
    execv("/bin/echo", exe_args);
#endif
    }
    return 0;
}

编译时,gcc 说,"passing argument 2 of 'execv' from incompatible pointer type" 如果我不使用强制转换。

execvPOSIX documentation(基本原理部分的一半)来看,第二个参数似乎是一个 char *const 数组,只是为了向后兼容:

The statement about argv[] and envp[] being constants is included to make explicit to future writers of language bindings that these objects are completely constant. ... It is unfortunate that the fourth column cannot be used...

其中 "fourth column" 指的是 const char* const[]

这里使用 (char **) 转换安全吗?我应该创建一个 char * 数组并将其传递给 execv 吗?

如果您只是打算放弃 const,那么您不应该一开始就使用 const。大多数(我敢说全部)编译器将接受以下代码

char *exe_name = "/bin/echo";
char *message = "You ran";
char *exe_args[] = { exe_name, message, argv[0], NULL };
execv( exe_args[0], exe_args );

如果这对你来说不够迂腐正确,那么另一个选择是

char exe_name[] = "/bin/echo";
char message[] = "You ran";
char *exe_args[] = { exe_name, message, argv[0], NULL };
execv( exe_args[0], exe_args );

请注意,execv 将复制字符串(为可执行文件创建 argv 数组),因此字符串实际上是否 [=12= 并不重要] 或不。

Can I pass an array of const char pointers as the second argument?

嗯,是的,你已经知道你可以施法来做到这一点。

From the POSIX documentation for execv (halfway through the Rationale section), it looks like the second argument is a char *const array only for backwards compatibility:

我不会用那些术语来表达,但是,是的,所选签名存在兼容性方面的问题。您引用的部分解释说,C 没有完全令人满意的方式来表达 POSIX 需要 execv() 来提供参数的 const-ness 的程度。 POSIX 保证该函数不会更改 argv 中的指针或它们指向的字符串。

在这种情况下,我认为按照您的建议转换 argv 指针并非不合理,尽管我会在我的代码中留下评论,解释为什么这样做是安全的。

另一方面,您应该考虑简单地将 const 从您的数组声明中删除:

char *exe_name = "echo", *message = "You ran";
char *exe_args[] = { exe_name, message, argv[0], NULL };

或者,在您的简单示例中,即使这样也可以:

char *exe_args[] = { "echo", message, argv[0], "You ran", NULL };

C 字符串文字对应于 char 类型的数组,而不是 const char,因此就 C 而言,这是完全合法的,即使实际尝试修改这些字符串的内容可能失败。

另一方面,现代 C 有数组文字,所以你甚至可以这样做:

execv("/bin/echo", (char *[]) { "echo", "You ran ", argv[0], NULL });

在最后一种情况下,你甚至没有强制转换(类似于一个的东西只是数组文字语法的一部分)。