为什么我们必须在打印地址在指针中的内存中的值之前将 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
它可以是任何东西。要取消引用,编译器需要知道类型,包括大小。
没有 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 *
的单独操作。
*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
的实现无法发现您提供的对象类型。)
我想知道为什么在打印内存中地址的内容之前必须将 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
它可以是任何东西。要取消引用,编译器需要知道类型,包括大小。
没有 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 *
的单独操作。
*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
的实现无法发现您提供的对象类型。)