我有一个关于GLib的简单问题.
我有以下代码:
static const char *words[] = { "one", "two", "three", NULL };
void main() {
puts(g_strjoinv("+", words));
}
Run Code Online (Sandbox Code Playgroud)
此代码打印one+two+three.它使用连接字符串的GLib函数.
该功能的签名是:
char *g_strjoinv (const char *separator, char **str_array);
Run Code Online (Sandbox Code Playgroud)
(确切地说,GLib使用的gchar不是char,但让我们忽略它.)
现在,我想知道为什么参数是char **str_array和不const char **str_array.它迫使我做一个显式的强制转换来摆脱编译器的警告("期望'char**'但参数类型为'const char**'"):
puts(g_strjoinv("+", (char **)words));
Run Code Online (Sandbox Code Playgroud)
我查看了GLib的参考资料,我发现所有函数都是这样定义的:它们接受char **,而不是const char **.
这是为什么?为什么GLib不使用const char **?
需要使用显式转换来摆脱const使得我的代码不那么安全(因为编译器不再检查参数的兼容性).这也让我感到紧张,因为GLib没有"签订合同",说它不会改变我的数据.
您的问题中的假设是,如果第二个参数g_strjoinv()被声明为类型const char **,那么您可以轻松地将a const char **或a 传递char **给它.
不幸的是,事实并非如此.正如comp.lang.c常见问题解答中的这个问题所解释的那样,使用指向预期指针的指针T(对于任何类型T)const T是可以的,但只有在不匹配位于顶层间接的情况下.也就是说,你可以通过一个char *其中const char *的预期,但你不(无投)通过一个可char **其中一个const char **预期,因为在这种情况下,不匹配是在间接的第二级.链接的问题详细解释了为什么它以这种方式工作,这是"有点模糊".
因此,结果是没有类型(在C中)将接受a char **和a const char **,其中至少有一个需要演员.在这种情况下,除了方便之外,可能没有太多理由偏爱,而图书馆的作者显然决定选择前者.作为纯粹推测的问题,我猜想想要传递a char **比想要传递a更常见const char **,因此他们选择的选项可能更方便.
在您的情况下,您可以const从数组的定义中删除限定符.如果你愿意的话const,这可能看起来很糟糕,但是由于你有一个指向字符串文字的指针数组,你的程序绝对有可能大声抱怨并且无论如何有任何想要写入它们的话都会失败,所以你不是真的在这种特殊情况下以任何有意义的方式失去安全.尽管尝试修改它们是未定义的行为,但字符串文字的类型数组char在C中,而不是数组const char(与C++不同).
稍微晦涩难懂,但即使你可以把它作为a传递const char **,这里的函数仍然可以修改指针,即使它不能修改它们所指向的内容,并且只是以不同的方式引起混乱,所以函数所做的承诺仍然不能保证传递给函数的内容不会以某种方式改变.