理解C/C++中"void"关键字的确切含义

inf*_*ler 11 c c++

如所解释的,例如,在这里,存在用于void关键字(更有经验的C/C++程序员可以跳到第四使用)3个主要用途:

1)作为不返回任何内容的函数的返回类型.这将导致代码示例如下:

void foo();
int i = foo();
Run Code Online (Sandbox Code Playgroud)

生成编译器错误.

2)作为函数参数列表中的唯一参数.AFAIK,一个空函数的参数列表与编译器完全相同,因此以下两行在含义上是相同的:( 编辑:它仅在c ++中为真.注释显示c中的差异).

int foo();
int foo(void);
Run Code Online (Sandbox Code Playgroud)

3)void*是一种特殊类型的通用指针 - 它可以指向任何未使用const或volatile关键字声明的变量,转换为/来自任何类型的数据指针,并指向所有非成员函数.另外,它不能被解除引用.我不会举例.

还有第四种用途,我不完全理解:

4)在条件编译中,它通常用在表达式(void)0中,如下所示:

// procedure that actually prints error message 
void _assert(char* file, int line, char* test); 
#ifdef NDEBUG 
#define assert(e) ((void)0) 
#else
#define assert(e)     \
((e) ? (void)0 :   \
__assert(__FILE__, __LINE__, #e)) 
#endif
Run Code Online (Sandbox Code Playgroud)

我试图通过实验来理解这个表达式的行为.以下所有内容均有效(编译良好):

int foo(); // some function declaration
int (*fooPtr)(); // function pointer
void(foo);
void(fooPtr);
void(0);
(void)0;
void('a');
void("blabla");
exampleClass e; //some class named exampleClass with a default ctor
void(e);
static_cast<void>(e);
Run Code Online (Sandbox Code Playgroud)

但这些不是:

void(0) // no semicolon
int i = void(0);
Run Code Online (Sandbox Code Playgroud)

我可以从中得出结论:"void" (在第4次使用的上下文中)只是一种特殊类型,任何类型都可以强制转换它(无论是c风格还是cpp风格),它永远不能用作左值或左值?

Che*_*Alf 7

我可以从中得出结论:"void"(在第4次使用的上下文中)只是一种特殊类型,任何类型都可以强制转换它(无论是c风格还是cpp风格),它永远不能用作左值或左值?

James McNellis在上面的评论中指出,void可以通过表达式用作右值void().

他从当前的C++标准中引用了这个:

C++11§5.2.3/ 2:
"表达式T(),其中是非数组完整对象类型T简单类型说明符类型名称说明,或者(可能是cv限定的)void类型,创建了一个prvalue指定的类型,它是值初始化的(不对该void()情况进行初始化)."

这使得编写代码成为可能......

template< class T >
T foo() { return T(); }
Run Code Online (Sandbox Code Playgroud)

并使用foo<void>()(很可能来自其他模板化代码,我会想象).

形式上void只是一种永远无法完成的不完整类型.

干杯和hth.


Kei*_*son 6

至于你的2),在C中这些:

int foo();
int foo(void);
Run Code Online (Sandbox Code Playgroud)

等价的.

第一种是旧式声明(在最新的C标准中仍然支持),它表示foo采用固定但未指定的数量和类型的参数.像呼叫foo(42)不需要诊断,但其行为是不确定的,除非定义foo说,它有一个int参数.

第二个具体说foo没有参数,foo(42)需要诊断.第二个宣言是原型; 第一个不是.在(void)因为一些特殊的语法需要能够声明无参数的功能,而无需编写的东西,看起来像一个老式的声明加入语法.

在新的C代码中,您应该始终使用原型.旧式声明仅保留在语言中以支持旧代码.

C++删除了旧式声明.在C++中,两个声明foo 等价的; int foo(void)仅支持与C兼容的表单

你的案例4)与条件编译没有任何直接关系.转换表达式void是一种评估表达式并明确丢弃其值的方法.它通常用于禁止警告.例如,如果foo()返回int结果,则

foo();
Run Code Online (Sandbox Code Playgroud)

作为独立语句可能会触发警告,表明您要丢弃结果,但是

(void)foo();
Run Code Online (Sandbox Code Playgroud)

可能告诉编译器你打算这样做.

void是一种无法完成的不完整类型.这意味着,类型的表达式void可以在不期望的值的上下文中使用.你是对的,类型的表达式void不能用作左值或右值. 编辑:除了Alf描述的情况,并且仅在C++中.