为什么在将地址在指针中的内存中打印之前,我们必须将void指针强制转换为int或其他内容?

我想知道为什么有必要在打印内存中的地址内容之前将void指针强制转换为int *char * ,即使我们告诉printf()函数如何解释内存中的数据?

假设我们有以下代码:

 int main (void) { void* c = malloc(4); printf("%d",*c); return 0; } 

为什么不可能这样做?

所以要明确我的问题是,这是不可能的原因是什么?

编辑:在所有答案和研究之后,我仍然不确定编辑中的致命错误究竟在哪里。 我感到困惑的主要原因是我的编译器(gcc)在告诉“取消引用void指针”时只给出一个警告。 这是实际的错误吗? 据我所知,即使有警告,该程序仍应编译。

EDIT2我仍然感到困惑的是,我们有一个ERROR和WARNING的原因似乎是完全独立的,但是由同一段代码生成:

 pointer.c:7:13: warning: dereferencing 'void *' pointer printf("%d",*p); ^~ pointer.c:7:13: error: invalid use of void expression printf("%d",*p); 

有些用户说只有在我们尝试使用derefenciation的结果时才会出现错误,并且警告是在我们为VOID指针实际分配内存时。

显然不是这种情况,因为如果我们删除printf行,我们确实只会得到一个警告但是完全没有一个警告。

 pointer.c:6:8: warning: unused variable 'p' [-Wunused-variable] void * p=malloc(4); 

问题不在于printf()的解释,而是取消引用。

在类似声明的情况下

  printf("%d",*c); 

你试图取消引用void * 。 现在, void是一个永远不完整的类型。 你不能取消引用一个指向“不完整的东西”的指针,并因此得到一些有意义的东西。

引用C11 ,章节§6.2.5,P19

void类型包含一组空值; 它是一个不完整的对象类型,无法完成。

换句话说(虽然我自己有点),C是一种强类型语言,对于每种定义的类型,编译器知道( 或必须知道 )它需要读取 /操作的内存中有多少字节(大小)上。 对于void类型,编译器是无能为力的。

出于同样的原因, void * s上也不允许使用指针算法。 gcc有一个扩展,它处理 void*char *相同,但这是一个扩展,而不是标准。


编辑:

我的编译器为语句生成错误, 在线检查

*c取消引用指针,其类型为void (不完整类型)。 你不能取消引用void ,因为编译器不知道类型(因此它的大小)。 因此,取消引用void指针会调用Undefined Behavior。

换句话说,取消引用void指针是不合理的。 想象一下,你是编译器,你将如何插入指针指向的内存(因为它可以是任何东西)? 将void*转换为正确的类型将起到作用(向编译器提供nessecairy信息)。

为什么编译器只发出警告而不是错误?

确实如此,请注意它会生成警告和伴随错误:

 main.c:8:14: warning: dereferencing 'void *' pointer printf("%d",*c); ^~ main.c:8:14: error: invalid use of void expression printf("%d",*c); ^~~~~~ 

(gcc)在讲述“取消引用void指针”时给出了一个警告。 这是实际的错误吗?

没有。

但是试图使用这种去除reflection的结果,你运气不好。

我的意思是:

 void* c = malloc(4); *c; 

不会导致错误(但只是警告):

 main.c:6:2: warning: dereferencing 'void *' pointer *c; ^~ 

但是,如果您尝试使用*c的结果,则会生成错误。

在了解无效指针的过程中阅读更多相关内容。

由于c是一个void pointer它可以是任何东西。 要取消引用,编译器需要知道类型,包括大小。

没有mallocvoid * ,请考虑这里发生的事情:

 int main() { int i = 555555; char * c = (char *)&i; printf("%c\n", *c); short * s = (short *)&i; printf("%d\n", *s); } 

你会得到非常不同的东西。 void *正在进行 – 它应该是什么?

你告诉printf期望一个数字,但这是一个单独的操作,首先解除void *

c指针已声明为void* 。 在访问/解除引用 void指针之前,您必须键入强制转换 ,以便它指向您在此指针中期望的相关类型。

总而言之,正如之前的答案所述, void在所有C标准中都是不完整的类型,因此每当您尝试取消引用它时,您肯定会收到错误。 但是,GNU C处理大小为1(char)的void,因此它只显示警告但GCC根据GNU扩展进行编译。

如果您希望GCC严格遵循标准,您必须添加-std=c11标志(可能使用-pedantic )。

printf没有指向要打印的东西,主要是因为它可以接受表达式的结果:

 printf("%d",4*my_function()); // value has no user-visible address 

因此,编译器必须知道类型才能获取并将其提供给printf 。 (你也需要格式字符串,因为语言提供了printf的实现,无法发现你给它的对象类型。)