void 在 C、C++ 和 C# 中意味着什么?
寻求了解术语“void”的来源以及为何称为 void 的基础知识。 这个问题的目的是帮助那些没有 C 经验但突然开始研究基于 C 的代码库的人。
Looking to get the fundamentals on where the term "void" comes from, and why it is called void. The intention of the question is to assist someone who has no C experience, and is suddenly looking at a C-based codebase.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(15)
在 C# 中,您可以使用 void 关键字来指示方法不返回值:
In C#, you'd use the void keyword to indicate that a method does not return a value:
我在大学里被教导“void”意味着“什么都没有”——这是一种错误的心理模型和反学习模式。
在 C/C++ 中,
void
意味着“无类型内存”。void
并不意味着“什么都没有”。 未定义的事物与没有事物不同。例如:MLT 视频框架为新返回一个
void *
分配的内存。如果 C/C++ 程序泄漏了
void *
内存,那么它肯定泄漏了某些东西。第一个函数将
void *
类型返回到新分配的“原始”内存。 物理内存只是一个 0/1 的数组。 原始物理内存对于编译器和程序员来说实际上也毫无意义。当程序员将
void *
转换为stuff *
或 填充数组。请注意,我们可以将
any *
转换为void *
,并将void *
转换为any *
。这让程序员可以编写
any *
代码,但可以使用void *
代码管理any
的内存。 这是设计的本质好处。该函数返回并接受
void *
指针。 此函数可用于扩展先前分配的数组的大小。在“空=无”心理模型中,将“无”重新分配为更多“无”是令人困惑的。
最终函数接受
void *
并返回void
。 返回的void
无法被赋值,这导致了void
没有任何意义的假设。返回
void
是一种语言约定,也是void
的“重载含义”。void *
是指向原始无类型内存的指针。I was taught "void" means "nothing" in college - it's a faulty mental model and an anti-learning pattern.
In C/C++
void
means "untyped memory".void
does not mean "nothing". An undefined thing is different than no thing.For example: MLT video framework returns a
void *
for newly allocated memory.If a C/C++ program leaks
void *
memory, it's definitely leaking something.The first function returns a
void *
type to a newly allocated "raw" memory. Physical memory is just an array of 0/1's. Raw physical memory is also practically meaningless for the compiler and programmer.The programmer creates meaning when he casts
void *
tostuff *
or a stuff array.Note that we can cast
any *
to avoid *
, andvoid *
toany *
.This let's the programmer write
any *
code, but manageany
's memory withvoid *
code. That's the essential benefit to the design.This function returns and accepts
void *
pointers. This function can be used to expand the size of a previously allocated array.Reallocating "nothing" to more "nothing" is confusing in a void=nothing mental model.
The final function accepts a
void *
and returnsvoid
. The returnedvoid
can't be assigned, which leads to the assumption thatvoid
means nothing.Returning
void
is a language convention and an "overloaded meaning" ofvoid
.A
void *
is a pointer to raw untyped memory.Void 是一种不完整类型,根据定义,它不能是左值。 这意味着它无法被赋值。
所以它也不能保持任何价值。
Void is an incomplete type which, by definition, can't be an lvalue. That means it can't get assigned a value.
So it also can't hold any value.
Void 仅在方法签名中使用。 对于返回类型,这意味着该方法不会向调用代码返回任何内容。 对于参数,这意味着没有参数传递给该方法。
例如,
在C#中我们可以省略参数的void,上面的代码可以这样写:
Void 不应该与 null 混淆。 Null 表示变量的地址在栈上,值在栈上。该地址的堆为空。
Void is used only in method signatures. For return types it means the method will not return anything to the calling code. For parameters it means no parameters are passed to the method.
E.g.,
In C# we can omit the void for parameters and can write the above code as:
Void should not be confused with null. Null means for the variable whose address is on stack, and the value on the heap for that address is empty.
void 意味着您不会从函数或方法返回任何值。
void means that you won't be returning any value from the function or method.
Void 意味着所有三种语言中函数的返回类型都不需要值。
Void means no value is required in the return type from a function in all of the three languages.
Void 相当于 Visual Basic 的 Sub。
Void is the equivalent of Visual Basic's Sub.
基本上它的意思是“无”或“无类型”
void 有 3 种基本的使用方式:
函数参数:
int myFunc(void)
-- 该函数不执行任何操作。
函数返回值:
void myFunc(int)
-- 函数不返回任何内容
通用数据指针:
void* data
-- 'data' 是指向未知类型数据的指针,无法取消引用
注意:函数参数中的
void
在 C++ 中是可选的,因此int myFunc()
与 int myFunc(void) 完全相同,并且在 C# 中被完全省略。 返回值始终需要它。Basically it means "nothing" or "no type"
There are 3 basic ways that void is used:
Function argument:
int myFunc(void)
-- the function takes nothing.
Function return value:
void myFunc(int)
-- the function returns nothing
Generic data pointer:
void* data
-- 'data' is a pointer to data of unknown type, and cannot be dereferenced
Note: the
void
in a function argument is optional in C++, soint myFunc()
is exactly the same asint myFunc(void)
, and it is left out completely in C#. It is always required for a return value.我一直认为它意味着缺席。 以下是 C 语言中与 不存在
R f(void)
的使用相匹配的四种情况 - 函数参数不存在void f(P)
- 返回值不存在void *p
- 指向的类型不存在( void) p
- 值的使用不存在其他 C 后代将其用于其他用途。 D 编程语言在初始化器不存在的情况下使用它 em>
T t = void;
- 初始化值不存在I have always taken it to mean absent. Here are four cases in the C language that matches to this use of absent
R f(void)
- Function parameters are absentvoid f(P)
- Return value is absentvoid *p
- Type of what is pointed to is absent(void) p
- Usage of value is absentOther C descendants use it for other things. The D programming language uses it for cases where an initializer is absent
T t = void;
- initializing value is absent有两种方法可以使用 void:
or
第一种表示没有传递任何参数或没有返回任何参数。
第二个告诉编译器没有与数据有效关联的类型,这意味着在将其转换为已知类型之前,您无法使用指向的数据。
例如,当您有一个接口调用一个无法提前知道参数的函数时,您会看到
void*
被大量使用。例如,在Linux内核中,当推迟工作时,您将设置一个要运行的函数 :
然后,内核线程将遍历延迟工作列表,当它到达此节点时,它会有效地执行
然后在 bar 中你有:
There are two ways to use void:
or
The first indicates that no argument is being passed or that no argument is being returned.
The second tells the compiler that there is no type associated with the data effectively meaning that the you can't make use of the data pointed to until it is cast to a known type.
For example you will see
void*
used a lot when you have an interface which calls a function whose parameters can't be known ahead of time.For example, in the Linux kernel, when deferring work you will set up a function to be run at a latter time by giving it a pointer to the function to be run and a pointer to the data to be passed to the function:
Then a kernel thread goes over a list of deferred work and when it gets to this node it effectively executes:
Then in bar you have:
意思是“没有价值”。 您可以使用
void
来指示函数不返回值或没有参数或两者兼而有之。 与英语中单词 void 的典型用法几乎一致。It means "no value". You use
void
to indicate that a function doesn't return a value or that it has no parameters or both. Pretty much consistent with typical uses of word void in English.它表示函数中没有返回值。
有些语言有两种子例程:过程和函数。 过程只是一系列操作,而函数是返回结果的一系列操作。
在C及其派生中,两者之间的区别并不明确。 一切基本上都是一个函数。
void
关键字表明它不是“实际”函数,因为它不返回值。It indicates the absence of a return value in a function.
Some languages have two sorts of subroutines: procedures and functions. Procedures are just a sequence of operations, whereas a function is a sequence of operations that return a result.
In C and its derivatives, the difference between the two is not explicit. Everything is basically a function. The
void
keyword indicates that it's not an "actual" function, since it doesn't return a value.void 的三个用例:
函数签名。
void foo(int bar)
不返回值。int bar(void)
不接受任何参数,但这通常用空参数列表表示:int bar()
。 这里使用的 void 关键字与其在英语中的含义相对应。通用顶级类型指针
void *
,指向未指定的数据且无法取消引用。 这里 void 的含义与 void 的其他含义不同:通用类型与无类型。在
(void) new Foo(this)
等强制转换中,表示故意丢弃返回值。 这里关键字的用法也符合其英文含义。@Gerald 已经涵盖了案例 1 和 2,但案例 3 尚未得到解决。
Three usage cases for void:
Function signatures.
void foo(int bar)
does not return a value.int bar(void)
does not take any parameters but this is usually expressed with empty argument list:int bar()
. Usage of the void keyword here corresponds to its meaning in English.Generic top-type pointer
void *
that points to unspecified data and cannot be dereferenced. Here the meaning of void is different from other meanings of void: universal type vs. no type.In casts such as
(void) new Foo(this)
to signify that the return value is deliberately thrown away. Here the keyword usage also matches its meaning in English.Cases 1 and 2 were already covered by @Gerald but case 3 has not been addressed yet.
将“空”视为“空结构”。 让我解释。
每个函数都采用一系列参数,其中每个参数都有一个类型。 事实上,我们可以将参数封装成一个结构体,结构体槽位与参数对应。 这使得每个函数都只有一个参数。 类似地,函数产生一个具有类型的结果。 它可以是布尔值,也可以是浮点数,也可以是包含任意一组其他类型值的结构体。 如果我们想要一种具有多个返回值的语言,很容易坚持将它们打包到一个结构中。 事实上,我们总是可以坚持认为函数返回一个结构。 现在,每个函数都只接受一个参数,并产生一个值。
现在,当我需要一个产生“无”值的函数时会发生什么?
好吧,考虑一下当我形成一个具有 3 个槽的结构时我会得到什么:
保存 3 个值。 当我有 2 个插槽时,它保存两个值。 当它
有一个槽位,一个值。 当它的槽位为零时,它保持......呃,
零值,或“无”值”。所以,我可以想到一个返回 void 的函数
返回一个不包含值的结构。 你甚至可以决定“无效”
只是空结构表示的类型的同义词,
而不是语言中的关键字(也许它只是预定义的类型:)
类似地,我可以将不需要值的函数视为接受空结构,例如“void”。
我什至可以通过这种方式实现我的编程语言。 传递空值
占用零字节,因此传递 void 值只是传递的一种特殊情况
其他任意大小的值。 这使得编译器很容易处理
“无效”结果或论证。 您可能需要语言功能
可能会丢弃函数结果; 在C中,如果你调用非void结果
函数 foo 在以下语句中:
富(...);
编译器知道 foo 产生结果并简单地忽略它。
如果 void 是一个值,那么这将完美地工作,现在是“过程”(即
只是一个带有 void 结果的函数的形容词)只是微不足道的特殊
一般函数的情况。
Void* 有点有趣。 我不认为 C 设计者想到了 void
以上方式; 他们刚刚创建了一个关键字。 当有人时该关键字可用
需要一个指向任意类型的点,因此 void* 作为 C 中的习惯用法。
如果您将 void 解释为空结构,它实际上效果很好。
void* 指针是空结构所在位置的地址
被放了。
对于其他类型T,从void*强制转换为T*,也从这个角度进行计算。
指针强制转换是一个完全的作弊行为,适用于大多数常见的体系结构,以利用以下事实:如果复合类型 T 的存储布局中物理上将子类型 S 的元素放置在 T 的开头,则将 S* 强制转换为 T* 并反之亦然,使用相同的物理机器地址往往会成功,因为大多数机器指针都有单一的表示形式。 用 void 类型替换 S 类型会产生完全相同的效果,因此可以进行到 void* 的强制转换。
PARLANSE 编程语言非常接近地实现了上述思想。
我们在它的设计上犯了错误,并没有密切关注“void”作为返回
类型,因此具有过程的语言关键字。 它大多只是一个简单的
语法改变,但这是你一旦得到后就无法抽出时间的事情之一
一种语言中的大型工作代码。
Think of void as the "empty structure". Let me explain.
Every function takes a sequence of parameters, where each parameter has a type. In fact, we could package up the parameters into a structure, with the structure slots corresponding to the parameters. This makes every function have exactly one argument. Similarly, functions produce a result, which has a type. It could be a boolean, or it could be float, or it could be a structure, containing an arbitrary set of other typed values. If we want a languge that has multiple return values, it is easy to just insist they be packaged into a structure. In fact, we could always insist that a function returned a structure. Now every function takes exactly one argument, and produces exactly one value.
Now, what happens when I need a function that produces "no" value?
Well, consider what I get when I form a struct with 3 slots: it
holds 3 values. When I have 2 slots, it holds two values. When it
has one slot, one value. And when it has zero slots, it holds... uh,
zero values, or "no" value". So, I can think of a function returning void
as returning a struct containing no values. You can even decide that "void"
is just a synonym for the type represented by the empty structure,
rather than a keyword in the language (maybe its just a predefined type :)
Similarly, I can think of a function requiring no values as accepting an empty structure, e.g., "void".
I can even implement my programming language this way. Passing a void value
takes up zero bytes, so passing void values is just a special case of passing
other values of arbitrary size. This makes it easy for the compiler to treat
the "void" result or argument. You probably want a langauge feature
that can throw a function result away; in C, if you call the non-void result
function foo in the following statement:
foo(...);
the compiler knows that foo produces a result and simply ignores it.
If void is a value, this works perfectly and now "procedures" (which are
just an adjective for a function with void result) are just trivial special
cases of general functions.
Void* is a bit funnier. I don't think the C designers thought of void in the
above way; they just created a keyword. That keyword was available when somebody
needed a point to an arbitrary type, thus void* as the idiom in C.
It actually works pretty well if you interpret void as an empty structure.
A void* pointer is the address of a place where that empty structure has
been put.
Casts from void* to T* for other types T, also work out with this perspective.
Pointer casts are a complete cheat that work on most common architectures to take advantage of the fact that if a compound type T has an element with subtype S placed physically at the beginning of T in its storage layout, then casting S* to T* and vice versa using the same physical machine address tends to work out, since most machine pointers have a single representation. Replacing the type S by the type void gives exactly the same effect, and thus casting to/from void* works out.
The PARLANSE programming language implements the above ideas pretty closely.
We goofed in its design, and didn't pay close attention to "void" as a return
type and thus have langauge keywords for procedure. Its mostly just a simple
syntax change but its one of things you don't get around to once you get
a large body working code in a language.
如果您向初学者解释这个概念,使用类比可能会有所帮助。 在所有这些情况下使用 void 的含义类似于书中的一页,其中有以下文字:“此页故意留白”。 它是为了让编译器区分应该标记为错误的类型和故意留空的类型,因为这是您想要的行为。
它总是出现在通常您希望看到类型出现的代码中,例如返回类型或指针类型。 这就是为什么在 C# 中,void 映射到实际的 CLR 类型 System.Void,因为它本身就是一种类型。
一些编程语言从未发展出空的概念,就像某些人类文化从未发明数字零的概念一样。 虚空在编程语言中代表着与零概念在人类语言中代表的进步相同的进步。
If you're explaining the concept to a beginner, it might be helpful to use an analogy. The use of void in all these cases is analogous in meaning to a page in a book which has the following words, "This page left intentionally blank." It is to differentiate to the compiler between something which should be flagged as an error, versus a type which is intentionally to be left blank because that is the behavior you want.
It always appears in code where normally you would expect to see a type appear, such as a return type or a pointer type. This is why in C#, void maps to an actual CLR type, System.Void because it is a type in itself.
Some programming languages never developed the concept of void, just like some human cultures never invented the concept of the number zero. Void represents the same advancement in a programming language as the concept of zero represents to human language.