将 const char** 转换为 void*?

Convert const char** to void*?

考虑这段代码:

#include <memory.h>
#include <stdlib.h>

void Foo()
{
  const char ** caps = malloc( sizeof( char * ) );
  memset( caps, 0, sizeof( char * ) );
}

使用 gcc 4.9.2 编译良好 -pedantic 但 cl 18(来自 VS2013 的那个)默认选项在 memset 行上显示 warning C4090: 'function' : different 'const' qualifiers

现在caps是指向const char的指针?所以指针本身不是 const 因此它应该转换为 void* 没有问题,我认为,但 cl 似乎自动从它生成 const void* 生成警告。这是对正在发生的事情的正确解释吗?这是非标准行为,对吧?

您不能将指向常量 (const X *) 的指针转换为 void *:那样会丢弃其 const 限定符。

memset 需要修改这些数据,这就是为什么它需要 void * 参数而不是 const void * 参数的原因。

按照你的写法,const指的是char,而不是指针。显然,分配内存只是为了声明它永远不会被修改(这意味着它永远不会被初始化)是没有意义的。

如果你希望指针本身是const,你应该这样写:

char ** const caps

您也可以将第二个指针设为常量,但这与将 char 设为常量一样没有意义。

编译器过于热心(读作:编译器错误)。

const char** caps 表示 caps 是一个指针(不是常量),指向另一个指向常量的 char 的指针(也不是常量)。也就是说,您保证不会通过遍及 caps.
的间接方式修改 char 这意味着您正式与编译器签订以下合同:

  1. 您可以更改 caps
  2. 您可以更改 *capscaps 指向的 char*)。
  3. 不允许更改**caps*caps指向的charcaps指向)) 通过这个链指针.
  4. 没有提及任何其他人(例如别名指针)更改该字符的值。

    const char **caps = malloc(sizeof(char *));

用一个合法的值初始化caps。如果 malloc 失败,这个值是一个空指针,但从语言的角度来看,这通常也是完全合法的(尽管它会导致下面的 memset 崩溃)。在 C++ 中,您需要显式转换 malloc 返回的 void*,但 C 允许这种事情就好了。

memset(caps, 0, sizeof(char*));

让我毛骨悚然(我是一名 C++ 程序员),但从 C 语言的角度来看,这仍然是一件完全合法的事情。
它所做的是覆盖到目前为止已分配但未初始化(并由 caps 指向)的内存块,该内存块包含第二个指针,其零字节数等于指针的大小(char指针,碰巧)。

库函数 memset 接受非常量 void*,只需用您提供的值(此处:零)。它不会,也不需要关心您与编译器签订的合同。但即便如此,它也没有违反任何规则。它覆盖指针,不是指向的常量值。
是的,它将几个 char 值写入 不是 数组 char 的东西(这就是为什么我的头发竖起来了),但是很好...那是...合法。毕竟,这正是 memset 应该做的,而且很可能 "work as expected"。它将指针设置为零位模式,除了一些非常罕见的奇特架构外,它对应于一个空指针。

内存位置 **caps 从未被更改(甚至被访问),因此所有这些都是完全合法的,您没有违背任何承诺。

因此警告是错误的。