将const char **转换为void *?

时间:2015-03-16 11:05:40

标签: c pointers visual-c++ gcc

考虑以下代码:

#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*生成警告。这是对正在发生的事情的正确解释吗?这是非标准行为,对吗?

3 个答案:

答案 0 :(得分:3)

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

const char** caps表示caps是一个指针(不是常数)指向不同的指针(也不是常量)到char是不变的。也就是说,您承诺不会通过char的间接来修改caps 这意味着您正式与编译器签订以下合同:

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

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

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

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

    让我的头发站起来(我是一名C ++程序员),但从C语言的角度来看它仍然是完全合法的。
    它的作用是覆盖到目前为止已分配但尚未初始化(并由caps指向的)内存块,该内存块包含第二个指针,其中零个字节的数量等于指针的大小({{1}指针,因为它发生)。

    库函数char采用非常量memset,只需用您提供的值(此处为零)填充您要求的字节数(此处为void*) 。关于您使用编译器签订的合同,它不需要也不需要关心。但即便如此,它也不违反任何规则。它会覆盖指针,指向的常量值 是的,它会将一些sizeof(char*)值写入不是 char的数组(这就是为什么我的头发会起立),但是很好。那...... 法律。它毕竟是char应该做的事情,并且它很可能会像预期的那样工作&#34;。它会将指针设置为零位模式,除了一些非常罕见的异构体系结构外,它对应于空指针。

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

    因此警告是错误的。

答案 1 :(得分:-3)

您无法将常量(const X *)指针投射到void *:这会丢弃其const限定符。

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

答案 2 :(得分:-3)

你写它的方式,const引用char,而不是指针。显然,仅仅分配内存以声明它永远不会被修改(这意味着它永远不会被初始化)是没有意义的。

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

char ** const caps

你也可以使第二个指针成为常量,但这比使用char const更有意义。