我想知道为什么在打印内存中的地址内容之前,有必要将void
指针强制转换为int *
或char *
,即使我们告诉{{1}函数如何解释内存中的数据?
假设我们有以下代码:
printf()
为什么不可能这样做?
所以要明确我的问题是这是不可能的原因是什么?
修改 在所有的答案和研究之后,我仍然不确定编辑中的致命错误究竟在哪里。我感到困惑的主要原因是我的编译器(gcc)在告诉“取消引用void指针”时只给出一个警告。这是实际的错误吗?据我所知,即使有警告,该程序仍应编译。
EDIT2 我仍然对我们有错误和警告的原因感到困惑,这些错误似乎是完全独立的,但是由同一段代码生成:
int main (void)
{
void* c = malloc(4);
printf("%d",*c);
return 0;
}
有些用户说只有在我们尝试使用derefenciation的结果时才会出现错误,并且警告是在我们为VOID指针实际分配内存时。
显然不是这种情况,因为如果我们删除printf行,我们确实只会收到一个警告但是完全没有一个警告。
pointer.c:7:13: warning: dereferencing 'void *' pointer
printf("%d",*p);
^~
pointer.c:7:13: error: invalid use of void expression
printf("%d",*p);
答案 0 :(得分:8)
问题不在于printf()
的解释,而在于取消引用。
对于像
这样的陈述 printf("%d",*c);
您正尝试取消引用void *
。现在,void
是一个永远不完整的类型。你不能取消引用指向“不完整的东西”并获得有意义的结果。
引用C11
,章节§6.2.5,P19
void类型包含一组空值;这是不完整的 无法完成的对象类型。
换句话说(虽然我自己有点),C是强类型语言,对于每个定义的类型,编译器知道(或必须知道)多少字节(大小)从内存中它需要读取 /操作。对于void
类型,编译器是无能为力的。
出于同样的原因,void *
上也不允许使用指针算法。 gcc有一个对待void*
的扩展名与char *
相同,但这是一个扩展名,而不是标准扩展名。
修改强>
我的编译器会为语句 check online 生成错误。
答案 1 :(得分:5)
*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* c = malloc(4);
*c;
不会导致错误(但只是警告):
main.c:6:2: warning: dereferencing 'void *' pointer
*c;
^~
但是,如果您尝试使用*c
的结果,则会生成错误。
答案 2 :(得分:3)
由于c
是void pointer
,因此它可以是任何内容。要取消引用,编译器需要知道类型,包括大小。
如果没有malloc
和void *
,请考虑这里发生的事情:
int main()
{
int i = 555555;
char * c = (char *)&i;
printf("%c\n", *c);
short * s = (short *)&i;
printf("%d\n", *s);
}
你会得到非常不同的东西。 void *
也是如此 - 这应该是什么?
您告诉printf
期待一个号码,但这是一个单独的操作,首先取消void *
。
答案 3 :(得分:0)
c
指针已声明为void*
。在访问/解除引用 void
指针之前,您需要必须输入强制转换,以便它指向您在此指针中期望的相关类型。
答案 4 :(得分:0)
总而言之,正如之前的答案所述,void
在所有C标准中都是不完整的类型。因此,每当您尝试取消引用它时,您肯定会收到错误。但是,GNU C处理的void大小为1(char)&因此它只显示警告,但GCC根据GNU扩展进行编译。
如果您希望GCC严格遵循标准,您必须添加-std=c11
标记(可能包含-pedantic
)。
答案 5 :(得分:0)
printf
没有将指针带到要打印的内容上,主要是因为它可以接受表达式的结果:
printf("%d",4*my_function()); // value has no user-visible address
因此,编译器必须知道类型才能获取值并将其提供给printf
。 (你还需要格式字符串 ,因为语言提供printf
的实现无法发现你给它的对象类型。)