将 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
这意味着您正式与编译器签订以下合同:
- 您可以更改
caps
。
- 您可以更改
*caps
(caps
指向的 char*
)。
- 您不允许更改
**caps
(*caps
指向的char
(caps
指向)) 通过这个链指针.
没有提及任何其他人(例如别名指针)更改该字符的值。
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
从未被更改(甚至被访问),因此所有这些都是完全合法的,您没有违背任何承诺。
因此警告是错误的。
考虑这段代码:
#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
这意味着您正式与编译器签订以下合同:
- 您可以更改
caps
。 - 您可以更改
*caps
(caps
指向的char*
)。 - 您不允许更改
**caps
(*caps
指向的char
(caps
指向)) 通过这个链指针. 没有提及任何其他人(例如别名指针)更改该字符的值。
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
从未被更改(甚至被访问),因此所有这些都是完全合法的,您没有违背任何承诺。
因此警告是错误的。