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

Why do we have to cast a void pointer to int or something else before printing the value in the memory whose address is in the pointer?

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

假设我们有以下代码:

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

为什么不能这样做?

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

编辑: 在所有的答案和研究之后,我仍然不确定编译中的致命错误到底在哪里。我感到困惑的主要原因是我的编译器 (gcc) 在讲述 "dereferencing a void pointer" 时只给出警告。这是实际错误吗?据我所知,即使有警告,该程序仍应编译。

EDIT2 我仍然对我们有一个 ERROR 和一个 WARNING 的原因感到困惑,这些 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);

一些用户说只有当我们尝试使用取消引用的结果时才会出现错误,而警告是当我们实际为 VOID 指针分配内存时。

这显然不是这种情况,因为如果我们删除 printf 行,我们确实只会收到一条警告,但却是一条完全不相关的警告。

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

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

在像这样的语句的情况下

 printf("%d",*c);

您正在尝试取消引用 void *。现在,void 是一个永远不完整的类型。您不能取消引用指向 "something incomplete" 的指针并得到有意义的结果。

引用 C11,章节 §6.2.5,P19

The void type comprises an empty set of values; it is an incomplete object type that cannot be completed.

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

出于同样的原因,在 void * 上也不允许使用指针算法。 gcc 有一个扩展 对待 a void*char * 相同,但那是一个扩展,不是标准的。


编辑:

我的编译器对 check online.

语句产生错误

因为 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 指针会调用未定义的行为。

换句话说,取消对空指针的引用是不合理的。想象你是编译器,你会如何解释指针指向的内存(因为它可以是任何东西)?将 void* 转换为正确的类型就可以了(向编译器提供必要的信息)。

Why does the compiler only gives a warning and not an error?

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

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) gives a WARNING when telling about "dereferencing a void pointer". Is this the actual error?

没有

但是尝试使用取消引用的结果,你就倒霉了。

我的意思是:

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

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

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

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

中阅读更多相关信息。

已声明 c 指针 void*。在 accessing/dereferencing void 指针之前,您需要 必须键入 cast,以便它指向您期望的相关类型在这个指针中。

总而言之,如之前的回答所述,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 的实现无法发现您提供的对象类型。)