我有一个问题,它可能已经在其他地方得到了回答,但我找不到它,所以如果它已经存在,我深表歉意。
我有以下代码:
#include <stdio.h>
void foo(double *number) {
printf("%fn", *number);
}
void bar(void *number) {
double *new_number = (double *)number;
printf("%fn", *new_number);
}
int main()
{
double test_number = 3.0;
double *test_double_pointer = &test_number;
void *test_void_pointer = (void *)test_double_pointer;
foo(test_double_pointer);
foo(test_void_pointer);
bar(test_double_pointer);
bar(test_void_pointer);
return 0;
}
结果是
3.000000
3.000000
3.000000
3.000000
我不明白引擎盖下发生了什么。C 编译器如何处理这些函数调用?
C 编译器如何处理这些函数调用?
编译器知道如何转换指针。具体说来
- 您的 C 编译器知道如何从
double *
转换为void *
。 - 您的 C 编译器知道如何从已转换为
void *
的double *
转换回double *
。
(在您可能使用的计算机上,不需要实际转换。
它知道什么时候该做。具体说来
- 当你投射到
void *
时,它知道它需要一个void *
。 - 当你投射到
double *
时,它知道它需要一个double *
。 - 当你分配给一个
void *
时,它知道它需要一个void *
。 - 当你分配给一个
double *
时,它知道它需要一个double *
。 - 当参数的类型为
void *
时,它知道它需要一个void *
参数。 - 当参数的类型为
double *
时,它知道它需要一个double *
参数。
(你没有做所有这些,但我想包括一些常见的情况。
您的代码是一个很好的示例,说明如何使用void
指针在函数之间传递任何类型的数据。
§6.3.2.3 指针 (C11 N1570)
- 指向
void
的指针可以转换为指向任何对象类型的指针,也可以从指向任何对象类型的指针相互转换。指向任何对象类型的指针都可以转换为指向void
的指针,然后再返回;结果应与原始指针相等。
在幕后没有发生太多事情,编译器必须确保上述规则得到尊重。执行此操作的一种简单方法是使所有指针类型的大小相同。
重要的是,编译器还需要知道指针类型,以便执行通常的指针算术和运算。
首先,变量名称有点混乱(编辑前的标题也是如此)。通常,双指针被理解为指向指针的指针,而不是指向double
的指针。
有人可能正在使用C++编译器来编译 C 代码。C++和C是不同的语言,有自己的规则。
在 C 语言中,您不需要从 或void *
进行转换。在C++中,它需要一个显式强制转换,并且没有强制转换的代码将不会编译 https://godbolt.org/z/78KbW4Wdz
在后台,编译器只需要知道指针引用的数据类型。
对于初学者,您可以按以下方式更改功能栏
void bar(void *number) {
double *new_number = number;
printf("%fn", *new_number);
}
删除显式强制转换。
在 C 中,void * 类型的指针可以分配给指向任何其他类型的对象的指针。
所以在这个电话中
foo(test_void_pointer);
bar(test_double_pointer);
void * 类型的指针可以分配给双精度 * 类型的参数,反之亦然,双精度 * 类型的指针可以分配给 void * 类型的参数。
来自 C 标准(6.3.2.3 指针)
1 指向 void 的指针可以转换为指向任何 对象类型。指向任何对象类型的指针都可以转换为 指向 void 并再次返回的指针;结果应等于 原始指针。