将const char**转换为void*?

sti*_*ijn 9 c gcc pointers visual-c++

考虑以下代码:

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

void Foo()
{
  const char ** caps = malloc( sizeof( char * ) );
  memset( caps, 0, sizeof( char * ) );
}
Run Code Online (Sandbox Code Playgroud)

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

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

Dam*_*mon 3

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

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

  1. 你可以改变caps
  2. 您可以更改*caps(指向的内容char*caps
  3. 您不能通过链指针更改**capschar指向*capscaps指向))。
  4. 没有提及任何其他人(例如别名指针)更改该字符的值。

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

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

memset(caps, 0, sizeof(char*));
Run Code Online (Sandbox Code Playgroud)

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

库函数memset采用非常量,只需用您提供的值(此处:零)void*填充您要求的字节数(此处)。sizeof(char*)它不会也不需要关心您与编译器签订的合同。但即便如此,它也没有违反任何规则。它覆盖指针,而不是指向的常量值。
是的,它把几个值写入到不是s数组的char东西中(这就是我头发竖起来的原因),但是……那是……合法的。毕竟,这正是应该做的,而且很可能“按预期工作”。它将指针设置为零位模式,除了一些非常罕见的奇异架构之外,它对应于空指针。charmemset

内存位置在任何时候都**caps没有改变(甚至没有被访问),所以所有这一切都是完全合法的,你没有违背任何承诺。

因此,该警告是错误的。