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