在 C++ 中传递 void 指针与将方法参数定义为 object
有何相似之处?如果您现在不知道该类型在编译时是什么?
最佳答案
让我们弄清楚其他答案中遗漏的一些事情。 C# 中的所有对象(结构除外)都作为指针传递。 C#(和 Java)隐藏了指针语法,因为它可能会出错,而且即使是经验最丰富的 C/C++ 程序员也会因滥用指针而无意中破坏堆,这是一件非常好的事情。
void *
在 C 中(以及在 C# 中 - 如果您打开不安全代码,它就会存在)是一个指向地址的指针,完全没有暗示它可能是什么。在 C 的早期,既没有 void
也没有 void *
。如果我们想要一个函数不返回任何内容,我们就没有放入 return 语句。它仍然是隐式的 int
,但值是不可预测的。如果没有 void *
,我们通常使用 char *
来代替,但程序员不喜欢那样,因为它暗示了一个指向字符或字符串的指针以及如何执行的暗示如果 sizeof(char) != 1
,指针上的数学运算。使用 void *
并不意味着您指向任何特定类型,程序员最清楚 void *
指向什么(剧透:大多数程序员不会)。
那你为什么要用这个?一个典型的用途是将指针用作 API 中的不透明类型。例如:
extern void *get_device();
extern int is_device_active(void *device);
这一切都很好——这个 API 的使用者不知道设备是什么。不幸的是,因为任何东西都是 void *
,这个 API 可以让你做一些非常可怕的事情:
char *str = get_device(); /* wrong */
size_t len = strlen(str); /* doubly wrong */
int active = is_device_active("hi mom!"); /* can't express how wrong */
然而,您的编译器会在没有窥视的情况下允许这样做,这实际上使得 void *
在这种情况下不是那么有用。
在 C# 中,object
完全是另一种野兽。它对指针的内容有非常强烈的暗示。它要么是 null
,要么是一个可以让您执行以下操作的类的实例:
- 等于
- 完成
- 获取哈希码
- 获取类型
- 成员克隆
- 到字符串
无论实际对象是什么,所有这些都保证存在。使用 void *
,除了 API 文档中的 promise 外,您什么都得不到。
void *
在 C 中的最佳用法是 malloc()
(及其变体)和 free()
,因为它们不指示它们指向什么类型。
此外,如果您想知道在 C 中实际如何呈现不透明的 API,典型的模式是:
/* device.h */
typedef struct t_device t_device;
extern t_device *get_device(); /* strongly typed now, but opaque */
extern int device_is_active(t_device *device);
/* device.c */
typedef struct t_device { /* this is private to the .c file */
int isActive; /* can't see it outside! Neener, neener! */
/* etc. */
} t_device;
t_device *get_device() { return make_device(); }
int device_is_active(t_device *device) { return device ? device->isActive : 0; }
关于c# - 函数参数中的空指针与对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27381861/