constness和指针指针

我对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); to const char** paths = malloc(count); ,此错误不再出现。 我不明白的是,那

  1. 我认为指向地址的指针总是可以转换为const指针,但不是相反的方式(这是imo发生的事情)。
  2. 这个例子有效: http : //codepad.org/mcPCMk3f

我做错了什么,或者我的错误在哪里?


编辑

我的目的是使输入数据的内存对于函数是不可变的。 (在本例中为paths参数)。

char ** – > 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而不是array-of- const char 。 这是出于历史原因。

我认为指向地址的指针总是可以转换为const指针

指向非const-T的指针可以转换为指向const-T的指针。 char ** - > const char**不是该模式的一个例子,因为如果Tchar *那么const Tchar * const ,而不是const char * (此时它可能不值得在左边写const更多:写char const * ,你不会期望它与T const相同,其中T是char * )。

您可以安全地将char **转换为char * const * ,并且(出于需要的不仅仅是简单规则的原因),您可以安全地将char **转换为char const * const *

关键是指针不是const。 要声明一个const指针,请使用char *const ptr; 或者声明一个指向const指针的const指针, char *const *const ptr;const char **ptr是指向const char指针。

实际上,如果有一个函数接受一个const char **并且你传递一个char **,这可能会导致一个有问题的情况,反之亦然。

在您的特定情况下,您期望内存是不可变的,但它不是不可变的,并且可能随时更改。 在multithreading环境中,您会期望此内存是线程安全的,只要它存在于堆栈或堆中,您就不需要使用互斥锁来访问它。

所有这些都是为了避免错误,但如果你确定这不会导致错误,你可以简单地将指针强制转换为const char **。

您不能将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. } 

如果没有函数调用,请参见此处的相同示例。