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

Posted

技术标签:

【中文标题】我可以将 const char* 数组传递给 execv 吗?【英文标题】:Can I pass a const char* array to execv? 【发布时间】:2016-04-28 21:00:57 【问题描述】:

这是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 说,如果我不使用强制转换,“从不兼容的指针类型传递 'execv' 的参数 2”。

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

包含关于 argv[]envp[] 是常量的声明是为了向未来的语言绑定编写者明确说明这些对象是完全常量。 ……可惜第四列不能用……

“第四列”指的是const char* const[]

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

【问题讨论】:

【参考方案1】:

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

嗯,是的,你已经知道你可以施放才能这样做。

从 execv 的 POSIX 文档(基本原理部分的一半)看来,第二个参数是一个 char *const 数组,只是为了向后兼容:

我不会这么说,但是是的,选择的签名有一个兼容性方面。您引用的部分解释说,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 );

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

【讨论】:

不知何故我认为字符串文字是const char。我想从我正在使用的变量中去掉const 毕竟并不是那么糟糕,尽管我开始认为要么我误解了 const 正确性,要么它在 C 中并不总是实用的。 @anaranjada,不,标准规定它们是 char 类型的数组,即使在实践中它们可能是不可写的。 GCC 可以选择使用 const char 的数组来代替,以帮助您找到可能会尝试写入其中的位置 - 也许这就是您的想法。 (因此,gcc 在您启用该选项时不符合要求。) 是的,我认为 GCC 选项让我失望。无论如何,我从我的代码中删除了一些 const 限定符,它现在编译时没有警告。谢谢。【参考方案2】:

如果你只是要抛弃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 数组),因此字符串实际上是否为const 并不重要。

【讨论】:

是的,你敢,至少如果你愿意将你的声明限制为符合编译器。根据标准,字符串文字对应于具有(非constchar 类型元素的静态数组。因此,您甚至不需要使用中间变量来形成数组初始值设定项。

以上是关于我可以将 const char* 数组传递给 execv 吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何将变量传递给 const char 类型?

以这种格式将 argv 变量传递给 main 的结果 main( int argc, char const * argv )

将数组作为 C++ 中方法的 const 参数传递

为什么将`const char [N]`和`const char *`传递给view :: c_str()会产生不同的二进制文件,而string_view会产生相同的结果吗?

如何将char赋给const char *

C++ 将 char 转换为 const char*