我经常在C ++中使用 execv()函数,但是如果某些参数是在C ++字符串中。令我很生气的是我不能这样做:
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 *不兼容所以我必须使用strdup将我的std :: strings复制到字符数组( )这是一种痛苦。
有谁知道这个的原因?
答案 0 :(得分:32)
Open Group Base规范解释了原因:为了与现有C代码兼容。但是,指针和字符串内容本身都不打算更改。因此,在这种情况下,您可以const_cast
使c_str()
的结果失效。
包含有关
argv[]
和envp[]
为常量的语句,以便明确将来语言绑定的编写者使这些对象完全不变。由于ISO C标准的限制,无法在标准C中陈述该想法。为执行的const
和argv[]
参数指定envp[]
的两个级别 - 资格函数似乎是自然的选择,因为这些函数不会修改指针数组或函数指向的字符,但这会禁止现有的正确代码。相反,只有指针数组被标记为常量。
之后的表格和文字更具洞察力。但是,Stack Overflow不允许插入表,因此上面的引用应该足以让您在链接文档中搜索正确的位置。
答案 1 :(得分:2)
const是一个C ++的东西 - execv在C ++存在之前已经采用了char *参数。
您可以使用const_cast而不是复制,因为execv实际上不会修改其参数。您可以考虑编写一个包装器来保存自己的输入。
实际上,代码的一个更大问题是你声明了一个字符数组而不是一个字符串数组。
尝试: const char * args [4];
答案 2 :(得分:1)
这只是C / C ++样式const不能很好地工作的情况。实际上,内核不会修改传递给exec()的参数。它只是在创建新进程时复制它们。但类型系统的表现力不足以真正处理好这个问题。
本页面上的很多人都建议让exec采用“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 **”的真正原因。
顺便说一句,C ++中的问题是相同的。你不能传递std :: vector< std :: string>到需要std :: vector<的函数const std :: string>。你必须强制转换或复制整个std :: vector。
答案 3 :(得分:-1)
我通常用以下方式入侵:
#define execve xexecve
#include <...>
#include <...>
#include <...>
#undef execve
// in case of c++
extern "C" {
int execve(const char * filename, char ** argvs, char * const * envp);
}
/