Void 在 C、 C++ 和 C# 中是什么意思?

期待得到的基本面术语“ void”来自哪里,为什么它被称为 void。这个问题的目的是帮助那些没有 C 经验却要查看基于 C 的代码库的人。

402199 次浏览

意思是“没有价值”。使用 void表示函数不返回值,或者表示函数没有参数,或者两者兼而有之。与英语中 无效这个词的典型用法非常一致。

在 C # 中,使用 无效关键字表示方法不返回值:

public void DoSomeWork()
{
// Some work
}

Void 仅用于方法签名。对于返回类型,这意味着该方法不会向调用代码返回任何内容。对于参数,它意味着不向方法传递任何参数。

例如:

void MethodThatReturnsAndTakesVoid(void)
{
// Method body
}

在 C # 中,我们可以省略参数的 void,并且可以编写以下代码:

void MethodThatReturnsAndTakesVoid()
{
// Method body
}

不应将 Void 与 null 混淆。 Null 表示其地址位于堆栈上的变量,而该地址在堆上的值为空。

它指示函数中没有返回值。

有些语言有两种子例程: 过程和函数。过程只是一系列操作,而函数是一系列返回结果的操作。

在 C 及其导数中,两者之间的区别是不明确的。基本上所有东西都是一个函数。void关键字表示它不是一个“实际”函数,因为它不返回值。

Void 意味着不会从函数或方法返回任何值。

基本上它的意思是“没有”或“没有类型”

使用 void 有三种基本方法:

  1. 函数参数: int myFunc(void) 函数不需要任何东西

  2. 函数返回值: void myFunc(int) 函数不返回任何值

  3. 泛型数据指针: void* data - “ data”是指向未知类型数据的指针,不能解除引用

注意: 函数参数中的 void在 C + + 中是可选的,所以 int myFunc()int myFunc(void)完全相同,而且在 C # 中完全省略了它。返回值总是需要它。

Void 意味着在所有三种语言中,函数的返回类型中不需要任何值。

有两种使用 void 的方法:

void foo(void);

或者

void *bar(void*);

第一个指示不传递任何参数或不返回任何参数。

第二种方法告诉编译器,没有与数据有效关联的类型,这意味着在将指向的数据强制转换为已知类型之前,不能使用它。

例如,当你有一个接口调用一个参数不能提前知道的函数时,你会看到 void*被大量使用。

例如,在 Linux 内核中,当延迟工作时,你将设置一个函数,通过给它一个指向要运行的函数的指针和一个指向要传递给该函数的数据的指针,在后一个时间运行该函数:

struct _deferred_work {
sruct list_head mylist;
.worker_func = bar;
.data        = somedata;
} deferred_work;

然后,一个内核线程遍历一个延迟的工作列表,当它到达这个节点时,它将有效地执行:

bar(somedata);

然后在 酒吧中你会看到:

void bar(void* mydata) {
int *data = mydata;
/* Do something with data */;
}

有三种使用情况:

  1. 函数签名。void foo(int bar)不返回值。int bar(void)不接受任何参数,但通常用空参数列表 int bar()表示。在这里使用 void 关键字与其在英语中的意思相对应。

  2. 指向未指定数据且不能取消引用的泛型顶类型指针 void *。在这里,void 的含义不同于 void 的其他含义: 普遍类型与非类型。

  3. 在类似 (void) new Foo(this)的强制转换中,表示返回值被故意丢弃。在这里,关键字的用法也与其在英语中的含义相匹配。

案例1和案例2已由@Gerald 处理,但案例3尚未处理。

Void 相当于 VisualBasic 的 Sub。

如果你要向初学者解释这个概念,用一个类比可能会有帮助。在所有这些情况下,void 的使用在意义上类似于书中的一页,其中有以下词语: “此页故意留空。”这是为了让编译器区分应该标记为错误的内容和故意留空的类型,因为这是您想要的行为。

它总是出现在通常希望看到类型出现的代码中,例如返回类型或指针类型。这就是为什么在 C # 中,void 映射到一个实际的 CLR 类型 System。因为它本身就是一种类型。

一些编程语言从未发展出 void 的概念,就像一些人类文化从未发明过数字零的概念一样。Void 代表了编程语言的进步,就像0这个概念代表了人类语言的进步一样。

我一直把它理解为 缺席。下面是 C 语言中与 缺席的这种使用相匹配的四种情况

  • 函数参数是 缺席
  • 返回值是 缺席
  • 指向的类型是 缺席
  • 值的使用是 缺席

其他 C 后代将其用于其他用途。D编程语言在初始化器为 缺席的情况下使用它

  • T t = void;-初始化值为 缺席

把 void 想象成“空结构”,让我解释一下。

每个函数都有一个参数序列,其中每个参数都有一个类型。实际上,我们可以将参数打包成一个结构,结构槽与参数相对应。这使得每个函数只有一个参数。类似地,函数生成一个结果,该结果具有一个类型。它可以是布尔型的,也可以是浮点型的,也可以是包含任意类型值集的结构体。如果我们想要一种具有多个返回值的语言,那么很容易坚持将它们打包成一个结构。事实上,我们总是坚持函数返回结构。现在每个函数只有一个参数,并且只产生一个值。

现在,当我需要一个产生“ no”值的函数时会发生什么? 考虑一下当我形成一个包含3个插槽的结构时会得到什么: it 持有3个值。当我有2个槽,它持有2个值。当它 只有一个插槽,一个值,当它没有插槽时,它保持.., 0值,或者“ no”值,所以,我可以想到一个返回 void 的函数 返回一个不包含任何值的结构 是空结构表示的类型的同义词, 而不是语言中的关键字(也许它只是一个预定义的类型:)

类似地,我可以把一个不需要值的函数想象成接受一个空结构,例如“ void”。

我甚至可以用这种方式实现我的编程语言 占用0个字节,所以传递 void 值只是传递 其他任意大小的值。这使得编译器很容易处理 “ void”结果或参数。您可能需要一个语言特性 它可以抛出函数 result; 在 C 中,如果调用 non-void 结果 函数 foo 在以下声明中: (...) ; 编译器知道 foo 会生成一个结果,而只是忽略它。 如果 void 是一个值,那么它可以完美地工作,现在“过程”(它是 只是一个形容词,表示函数的 void 结果)只是平凡的特殊 一般函数的例子。

Void * 更有趣一点。我不认为 C 设计师在 他们刚刚创建了一个关键字 需要一个指向任意类型的点,因此 void * 作为 C 语言中的成语。 如果您将 void 解释为空结构,那么它实际上工作得非常好。 Void * 指针是空结构所在位置的地址 已经放下了。

对于其他类型 T,从 void * 到 T * 的转换,也可以使用这个透视图。 指针强制转换是一种完全的欺骗,它在大多数常见的架构中都起作用,它利用了这样一个事实: 如果一个复合类型 T 的存储布局中有一个子类型 S 的元素物理地放置在 T 的开头,那么使用相同的物理机器地址强制转换 S * 到 T * ,反之亦然,因为大多数机器指针都有一个单一的表示。用 void 类型替换类型 S 会产生完全相同的效果,因此在 void * 中进行类型转换是可行的。

PARLANSE 编程语言非常紧密地实现了上述思想。 我们在它的设计上犯了错误,没有密切关注作为回报的“无效” 类型,因此有语言关键字的过程。它大多只是一个简单的 语法改变,但是一旦你得到 用一种语言编写的大体工作代码。

Void 是一个不完整的类型,根据定义,它不能是左值,这意味着它不能被赋值。

所以它也不能保持任何价值。

在大学里,我被教导“空虚”意味着“什么都没有”——这是一种错误的心理模式,是一种反学习模式。

在 C/C + + 中,void的意思是“非类型化内存”。void并不意味着“没有”。未定义的东西和没有东西是不一样的。

例如: MLT 视频框架 为新分配的内存返回一个 void *

如果一个 C/C + + 程序泄漏了 void *内存,那么它肯定泄漏了什么东西。

void *mlt_pool_alloc( int size );
void *mlt_pool_realloc( void *ptr, int size );
void mlt_pool_release( void *release );

第一个函数将 void *类型返回给新分配的“原始”内存。物理内存只是0/1的数组。对于编译器和程序员来说,原始物理内存实际上也是毫无意义的。

当程序员将 void *转换为 stuff *东西数组时,就创建了意义。

注意,我们可以将 any *转换为 void *,将 void *转换为 any *

这让程序员编写 any *代码,但是用 void *代码管理 any的内存。这是设计的根本好处。

// Resize allocated memory
void *mlt_pool_realloc( void *ptr, int size );

此函数返回并接受 void *指针。此函数可用于扩展先前分配的数组的大小。

将“无”重新分配到更多的“无”在一个空 = 无的心理模型中是令人困惑的。

void mlt_pool_release( void *release );

最后一个函数接受 void *并返回 void。返回的 void不能被分配,这导致了 void没有任何意义的假设。

返回 void是一种语言约定,也是 void的“重载意义”。

void *是指向原始非类型化内存的指针。