const void *
和void *
之间有什么区别?在什么情况下可以将void指针强制转换为const void
指针?
答案 0 :(得分:31)
const void *
指向不应修改的内存。
void *
(非const)指向可以修改的内存(但不是通过void *
;你必须先将其强制转换。)
使用memmove()
时,源地址将转换为const void *
:
void *memmove(void *dst, const void *src, size_t nbytes);
这是一个插图,可以将void指针强制转换为常量void指针。基本上,当您知道不打算修改指针所指向的内存时,您可以随时执行此操作(转换为常量)。这适用于任何指针 - 而不仅仅是void指针。
转换另一种方式(从常量指针转换为非常量指针)是一项更危险的练习。无法保证指向的内存实际上是可修改的;例如,字符串文字可以存储在只读(常量)内存中,如果你失去了使用强制转换的常量并尝试修改字符串,你可能会遇到分段错误或等效错误 - 你的程序会突然停止而不是在你的控制之下。这不是一件好事。所以,不要将指针从常量更改为非常量而不确定它实际上可以骗你的编译器。请注意编译器不喜欢被骗,并且可以自己回来,通常是在最不方便的时刻(例如在向老板面前的重要潜在客户展示您的程序,老板的老板和老板老板的老板) )。
答案 1 :(得分:7)
将void *
强制转换为const void *
是完全合理的,编译器应该在幕后隐式地这样做,而不需要你的任何想法,但另一种方式是危险的,必须避免。
请记住,如果某个函数使用const
指针,那么您可以自由地将const
或非const
值传递给它。假设您使用const
指针只是声明您的函数不会修改内存。
示例:(请注意,标记为 DANGER 的行应该抛出编译器错误)
const void *p_const;
void *p_buffer;
// const pointers are allowed to hold static memory
p_const = "Foo"; // allowed
p_buffer = "Foo"; // DANGER!!!
// casting to const is implicit
p_const = malloc(LEN); // allowed - implicit cast
p_buffer = malloc(LEN); // allowed
// casting to const implicit again
write(STDOUT, p_const, LEN); // allowed
write(STDOUT, p_buffer, LEN); // also allowed - implicit cast
// const memory cannot be used where mutable memory is expected
read(0, p_buffer, LEN); // allowed
read(0, p_const, LEN); // DANGER!!
// To make the above more obivous, we'll skip the intermediate variable
// and place instead what it holds
read(0, malloc(LEN), LEN); // allowed - useless but at least no crashes
read(0, "foo", 4); // DANGER!!!
作为一般规则,如果您编写的函数接收指向您不会修改的值的指针,则函数签名应使用const
指针。使用未声明为const
的指针意味着允许修改您指向的内存。
另一个例子:
void do_something(const void* ptr, int length);
// Since the signature is a const pointer, I know I can call it like this:
do_something("foo",4);
相反,函数调用非常量指针,然后我必须允许它:
void do_something(void* ptr, int length);
// This tells me that the function may overwrite my value.
// The safe solution therefore looks more like this:
char *myptr = char[4];
memcpy(myptr,"foo",4);
do_something(myptr,4);
同样,如果您发现自己处于需要将const
指针强加给非const
指针的情况,则应将指向值复制到内存的可变部分,并将您的副本传递给函数而不是原始函数。如果这听起来很头疼,那是因为它是。如果你发现自己处于那种情况,那么你可能做错了什么。
从概念上讲,如果变量包含“值”,那么它可能是const
指针。如果它拥有一个“缓冲区”,那么它就是一个非const
指针。
除非您打算写入该内存,否则函数签名中的指针应始终声明为const
。遵循该规则将帮助您避免程序逻辑中的灾难性问题。
在我编程6年之前,我不明白这个简单的规则。