2

我对const关键字感到非常困惑。我有一个接受字符串数组作为输入参数的函数和一个接受可变数量参数的函数。

void dtree_joinpaths(char* output_buffer, int count, ...);
void dtree_joinpaths_a(char* output_buffer, int count, const char** paths);

dtree_joinpathsdtree_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);,此错误不再出现。我不明白的是,

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

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


编辑

我的目的是使输入数据的内存对于函数不可变。(在这种情况下是paths参数)。

4

4 回答 4

5

原因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**不是该模式的示例,因为 if Tis char *then const Tis char * const, not const char *(此时可能值得不再const在左侧写 the :写char const *,你不会期望它与T constwhere T is char *)。

您可以安全地转换char **char * const *, 并且(出于需要比简单规则多一点的原因)您可以安全地转换char **char const * const *.

于 2013-01-21T16:56:23.260 回答
1

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

于 2013-01-21T15:35:27.483 回答
0

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

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

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

于 2013-01-21T15:57:49.047 回答
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.
}

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

于 2013-01-21T16:55:57.050 回答