为什么 void 在 C++ 中不取 void 值?
Why doesn't void take a void value in C++?
我很好奇为什么C++不通过以下方式定义 void:
typedef struct { } void;
即,即使该安装必须不生成代码,也无法实例化的类型中的值是多少?
如果我们使用 gcc -O3 -S
,那么以下两个都会生成相同的汇编程序:
int main() { return 0; }
和
template <class T> T f(T a) { }
typedef struct { } moo;
int main() { moo a; f(a); return 0; }
这是完全有道理的。 struct { }
只是取一个空值,很容易优化。 实际上,奇怪的部分是它们在没有-O3
的情况下生成不同的代码。
然而,你不能简单地用typedef void moo
来拉出同样的把戏,因为空不能假设任何价值,即使是空的。 这种区别有什么用处吗?
还有其他各种强类型语言,如 Haskell,大概还有 ML,它们的 void 类型具有值,但没有公开提供无价值类型,尽管有些拥有本机指针类型,它们的行为类似于void *
。
我认为void
无法实例化的理由来自C++的C根。在过去血腥的日子里,类型安全并不是什么大问题,void*
不断被传递。但是,您可能总是看到的代码没有字面意思说void*
(由于typedef
、宏和C++中的模板(,但仍然有意义。
如果您不能取消引用void*
但必须首先将其强制转换为指向正确类型的指针,则这是一点点安全性。无论你是按照 Ben Voigt 的建议使用不完整的类型来实现,还是使用内置的void
类型都无关紧要。您可以避免错误地猜测您正在处理一个类型,而您不是。
是的,void
引入了烦人的特殊情况,尤其是在设计模板时。但是编译器不会默默接受实例化void
的尝试是一件好事(即故意的(。
不会使void
成为一个不完整的类型,现在呢?
使用以下命令再次尝试示例代码:
struct x; // incomplete
typedef x moo;
为什么
void
应该是不完整的类型?
原因有很多。
最简单的是:moo FuncName(...)
仍然必须返回一些东西。无论是中性值,还是"非值值",或者其他什么;它仍然必须说return value;
,其中value
是一些实际值。它必须说return moo();
.
为什么要编写一个在技术上返回某些内容的函数,而它实际上并没有返回某些内容?编译器无法优化返回输出,因为它返回的是完整类型的值。调用方可能实际使用它。
你知道,C++并不全是模板。编译器不一定具有将所有内容都扔掉的知识。它通常必须执行函数内优化,而这些优化不知道该代码的外部使用。
在这种情况下,void
的意思是"我不归还任何东西"。这和"我返回一个无意义的值"之间有一个根本的区别。这样做是合法的:
moo FuncName(...) { return moo(); }
moo x = FuncName(...);
这充其量是误导。粗略扫描表明正在返回和存储值。标识符x
现在具有值,可用于某些内容。
而这:
void FuncName(...) {}
void x = FuncName(...);
是编译器错误。这也是这样的:
void FuncName(...) {}
moo x = FuncName(...);
很明显发生了什么:FuncName
没有返回值。
即使您从头开始设计C++,没有来自 C 的保留,您仍然需要一些关键字来指示返回值的函数和不返回值的函数之间的区别。
此外,void*
之所以特殊void
部分原因是它不是一个完整的类型。由于标准要求它不是一个完整的类型,因此void*
的概念可能意味着"指向非类型化内存的指针"。这具有专门的转换语义。指向类型化内存的指针可以隐式转换为非类型化内存。指向非类型化内存的指针可以显式转换回它以前的类型化指针。
如果你改用moo*
,那么语义就会变得奇怪。您有一个指向类型化内存的指针。目前,C++将不相关的类型指针之间的强制转换(某些特殊情况除外(定义为未定义的行为。现在,标准必须为 moo
类型添加另一个例外。它必须说明当你这样做时会发生什么:
moo *m = new moo;
*moo;
对于void
,这是一个编译器错误。moo
是怎么回事?它仍然是无用和无意义的,但编译器必须允许它。
老实说,我会说更好的问题是"为什么void
应该是一个完整的类型?
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- 在c++类上调用void函数
- 为什么野牛仍在使用"int yylex(void)",却找不到"int yylex(YYS
- 在派生函数中指定void*参数
- C++为什么尽管我调用了void函数,它却不起作用
- 如何从void函数输出字符串
- 我应该使用什么来代替void作为变体中的替代类型之一
- 奇怪的结构&GCC&clang(void*返回类型)
- Arduino:for/while/if在void setup()或void loop()之前?——错误:之前需要不合格
- 为什么这个函数将"const char*"转换为"void* const"而不是"const void*"
- 引用一个已擦除类型(void*)的指针
- 将尾部调用void(i32,..)位转换为llvm::函数以获取FnAttribute
- 库函数需要一个 std::function<void(void)>,如何传入类函数?
- 如何将指针从一个void函数传递到另一个C++
- 为什么我在使用void函数时得到错误代码C2276
- void*到驱动程序中的UnicodeString
- 为什么在逗号分隔符上下文中将预增量的结果强制转换为void
- 指针没有更新它在void函数内部指向的值
- 不能将 "void *" 类型的值分配给类型 "TCHAR" 的实体
- 错误:在为指针赋值时,void值没有被忽略