我对const
关键字感到非常困惑。我有一个函数接受一个字符串数组作为输入参数和一个接受可变数量参数的函数。
void dtree_joinpaths(char* output_buffer, int count, ...);
void dtree_joinpaths_a(char* output_buffer, int count, const char** paths);
dtree_joinpaths
在从参数列表构建了一个字符串数组后,在内部调用dtree_joinpaths_a
。
void dtree_joinpaths(char* output_buffer, int count, ...) {
int i;
va_list arg_list;
va_start(arg_list, count);
char** paths = malloc(sizeof(char*) * count);
for (i=0; i < count; i++) {
paths[i] = va_arg(arg_list, char*);
}
va_end(arg_list);
dtree_joinpaths_a(output_buffer, count, paths);
}
但gcc
编译器给出了以下错误消息:
src/dtree_path.c: In function 'dtree_joinpaths':
src/dtree_path.c:65: warning: passing argument 3 of 'dtree_joinpaths_a' from incompatible pointer type
当我将char** paths = malloc(count);
更改为const char** paths = malloc(count);
时,此错误不再显示。我不明白的是那个
我做错了什么,或者我的误解在哪里?
我的目的是使输入数据的内存对于函数是不可变的。 (在本例中为paths
参数)。
答案 0 :(得分:5)
原因char **
- &gt; const char**
是一个“危险”的转换,代码如下:
const char immutable[] = "don't modify this";
void get_immutable_str(const char **p) {
*p = immutable;
return;
}
int main() {
char *ptr;
get_immutable_str(&ptr); // <--- here is the dangerous conversion
ptr[0] = 0;
}
上面的代码试图修改一个不可修改的对象(const char
的全局数组),这是未定义的行为。在这段代码中没有其他候选者可以定义为“坏”,所以const-safety指示指针转换是坏的。
C并不禁止转换,但是gcc
警告你这很糟糕。仅供参考,C ++确实禁止转换,它具有比C更严格的const安全性。
我会在示例中使用字符串文字,但C中的字符串文字开头是“危险的” - 您不允许修改它们但它们的类型为array-of - char
而不是数组 - const char
。这是出于历史原因。
我认为指向地址的指针总是可以转换为const指针
指向非const-T的指针可以转换为指向const-T的指针。 char **
- &gt; const char**
不是该模式的示例,因为如果T
为char *
,那么const T
为char * const
,而不是const char *
(此时可能不值得再写左边的const
:写char const *
,你不会期望它与T const
相同,其中T是char *
)。
您可以安全地将char **
转换为char * const *
,并且(出于需要更多简单规则的原因),您可以安全地将char **
转换为char const * const *
。
答案 1 :(得分:1)
关键是指针不是const。要声明一个const指针,请使用char *const ptr;
或声明一个指向const指针char *const *const ptr;
的const指针。 const char **ptr
是指向const char
的指针。
答案 2 :(得分:0)
实际上,如果有一个函数接受一个const char **并且你传递一个char **,这可能会导致一个有问题的情况,反之亦然。
在您的特定情况下,您希望内存是不可变的,但它不是不可变的,并且可能随时更改。在多线程环境中,您会期望此内存是线程安全的,只要它存在于堆栈或堆中,您就不需要使用互斥锁来访问它。
所有这些都是为了避免错误,但是如果你确定这不会导致错误,你可以简单地将指针强制转换为const char **。
答案 3 :(得分:0)
您无法将char **
传递给const char **
,因为编译器无法保证const正确性。
假设您有以下代码(并且已编译):
void foo(const char **ppc, const char* pc)
{
*ppc = pc; // Assign const char* to const char*
}
void bar()
{
const char c = 'x';
char* pc;
foo(&pc, &c); // Illegal; converting const char* to const char**. Will set p == &c
*pc = 'X'; // Ooops! That changed c.
}
有关没有函数调用的相同示例,请参阅here。