【发布时间】:2010-11-05 19:04:41
【问题描述】:
希望了解有关“void”一词的来源以及为什么将其称为 void 的基本知识。这个问题的目的是帮助那些没有 C 经验的人,突然开始研究基于 C 的代码库。
【问题讨论】:
-
这个问题混合了 3 种语言......这个遗留问题应该分成 3 个不同的问题。
标签: c# c++ c language-design terminology
希望了解有关“void”一词的来源以及为什么将其称为 void 的基本知识。这个问题的目的是帮助那些没有 C 经验的人,突然开始研究基于 C 的代码库。
【问题讨论】:
标签: c# c++ c language-design terminology
意思是“没有价值”。您使用void 表示函数不返回值或它没有参数或两者兼而有之。与英语中单词 void 的典型用法非常一致。
【讨论】:
在 C# 中,您可以使用 void 关键字来指示方法不返回值:
public void DoSomeWork()
{
// Some work
}
【讨论】:
Void 仅用于方法签名。对于返回类型,这意味着该方法不会向调用代码返回任何内容。对于参数,这意味着没有参数传递给方法。
例如,
void MethodThatReturnsAndTakesVoid(void)
{
// Method body
}
在C#中我们可以省略参数的void,可以将上面的代码写成:
void MethodThatReturnsAndTakesVoid()
{
// Method body
}
Void 不应与 null 混淆。 Null 表示地址在堆栈上的变量,而该地址在堆上的值为空。
【讨论】:
表示函数中没有返回值。
有些语言有两种子例程:过程和函数。过程只是一个操作序列,而函数是一个返回结果的操作序列。
在 C 及其衍生物中,两者之间的区别并不明确。一切基本上都是一个函数。 void 关键字表明它不是“实际”函数,因为它不返回值。
【讨论】:
void 表示您不会从函数或方法返回任何值。
【讨论】:
基本上它的意思是“没有”或“没有类型”
void 的使用有 3 种基本方式:
函数参数:int myFunc(void)
-- 该函数什么都不带。
函数返回值:void myFunc(int)
-- 函数不返回任何内容
通用数据指针:void* data
-- 'data' 是指向未知类型数据的指针,不能被解引用
注意:函数参数中的 void 在 C++ 中是可选的,因此 int myFunc() 与 int myFunc(void) 完全相同,在 C# 中完全省略了它。它始终是返回值所必需的。
【讨论】:
Void 表示所有三种语言的函数的返回类型都不需要值。
【讨论】:
void有两种使用方式:
void foo(void);
或
void *bar(void*);
第一个表示没有参数被传递或没有参数被返回。
第二个告诉编译器没有与数据关联的类型,这意味着在将其转换为已知类型之前,您无法使用指向的数据。
例如,当您的接口调用无法提前知道参数的函数时,您会看到void* 被大量使用。
例如,在Linux kernel 中,当推迟工作时,您将设置一个稍后运行的函数,方法是给它一个指向要运行的函数的指针和一个指向要传递给功能:
struct _deferred_work {
sruct list_head mylist;
.worker_func = bar;
.data = somedata;
} deferred_work;
然后一个内核线程遍历一个延迟工作列表,当它到达这个节点时它有效地执行:
bar(somedata);
然后在 bar 你有:
void bar(void* mydata) {
int *data = mydata;
/* Do something with data */;
}
【讨论】:
void的三种使用案例:
函数签名。 void foo(int bar) 不返回值。 int bar(void) 不接受任何参数,但这通常用空参数列表表示:int bar()。此处void关键字的用法与其英文含义相对应。
通用顶级类型指针void *,指向未指定的数据,无法取消引用。这里void的含义与void的其他含义不同:universal type vs. no type。
在诸如(void) new Foo(this) 之类的强制转换中表示有意丢弃返回值。这里的关键字用法也符合它的英文含义。
@Gerald 已涵盖案例 1 和案例 2,但案例 3 尚未解决。
【讨论】:
Void 相当于 Visual Basic 的 Sub。
【讨论】:
如果您要向初学者解释这个概念,使用类比可能会有所帮助。在所有这些情况下使用 void 的含义类似于一本书中的一页,其中包含以下词语:“此页故意留白”。这是为了区分编译器应该标记为错误的内容与故意留空的类型,因为这是您想要的行为。
它总是出现在您通常希望看到类型出现的代码中,例如返回类型或指针类型。这就是为什么在 C# 中,void 映射到一个实际的 CLR 类型 System.Void,因为它本身就是一个类型。
一些编程语言从未发展出 void 的概念,就像一些人类文化从未发明过数字零的概念一样。 Void 代表编程语言的进步,就像零的概念代表人类语言一样。
【讨论】:
我一直认为它的意思是缺席。以下是 C 语言中与 absent
的这种用法相匹配的四种情况R f(void) - 函数参数不存在
void f(P) - 返回值不存在
void *p - 所指向的类型是不存在
(void) p - 值的使用不存在
其他 C 后代将它用于其他事情。 D 编程语言将它用于初始化器不存在
的情况T t = void; - 初始化值不存在
【讨论】:
(void)p 是做什么的?我不太明白你所说的“没有使用价值”是什么意思。
(void) var; 声明感到困惑,我在stackoverflow.com/q/21045615 找到了详细答案。
将 void 视为“空结构”。让我解释一下。
每个函数都接受一系列参数,其中每个参数都有一个类型。实际上,我们可以将参数打包成一个结构体,结构体槽位对应参数。这使得每个函数都只有一个参数。类似地,函数产生一个结果,它有一个类型。它可以是布尔值,也可以是浮点数,也可以是包含任意其他类型值集的结构。如果我们想要一个具有多个返回值的语言,很容易坚持将它们打包成一个结构。事实上,我们总是可以坚持一个函数返回一个结构。现在每个函数都只接受一个参数,并且只产生一个值。
现在,当我需要一个产生“无”值的函数时会发生什么? 好吧,考虑一下当我形成一个具有 3 个插槽的结构时得到的结果: 持有 3 个值。当我有 2 个插槽时,它包含两个值。当它 有一个槽,一个值。当它的槽位为零时,它持有......呃, 零值或“无”值”。所以,我可以想到一个返回 void 的函数 作为返回一个不包含值的结构。你甚至可以决定“无效” 只是空结构所表示的类型的同义词, 而不是语言中的关键字(也许它只是一个预定义的类型:)
同样,我可以将不需要值的函数视为接受空结构,例如“void”。
我什至可以通过这种方式实现我的编程语言。传递一个空值 占用零字节,因此传递 void 值只是传递的一种特殊情况 其他任意大小的值。这使得编译器很容易处理 “无效”的结果或论点。你可能想要一个语言功能 可以丢弃函数结果;在 C 中,如果您调用非 void 结果 函数 foo 在以下语句中: 富(...); 编译器知道 foo 会产生结果并简单地忽略它。 如果 void 是一个值,那么它可以完美地工作,现在是“程序”(它们是 只是具有 void 结果的函数的形容词)只是微不足道的特殊 一般函数的情况。
Void* 有点好笑。我不认为 C 设计者在 以上方式;他们刚刚创建了一个关键字。该关键字在有人可用时可用 需要一个指向任意类型的点,因此 void* 作为 C 中的成语。 如果您将 void 解释为空结构,它实际上工作得很好。 void* 指针是该空结构所在位置的地址 被放了。
对于其他类型 T,从 void* 到 T* 的转换,也适用于这个视角。 指针转换是一种完整的作弊方法,适用于大多数常见架构,以利用以下事实:如果复合类型 T 在其存储布局中具有子类型 S 的元素物理放置在 T 的开头,则将 S* 转换为 T* 和反之亦然,使用相同的物理机器地址往往会解决问题,因为大多数机器指针都有一个单一的表示。将类型 S 替换为 void 类型会产生完全相同的效果,因此可以与 void* 进行强制转换。
PARLANSE 编程语言非常接近地实现了上述想法。 我们在它的设计上搞砸了,并没有密切关注“无效”作为回报 类型,因此具有过程的语言关键字。它大多只是一个简单的 语法发生了变化,但这是您一旦获得就无法解决的事情之一 一种语言的大型工作代码。
【讨论】:
Void 是一个不完整的类型,根据定义,它不能是左值。这意味着它不能被赋值。
所以它也不能保持任何价值。
【讨论】: