As explained, for example, here, there are 3 main uses for the void keyword (more experienced C/C++ programmers can skip to the 4th use):
1) As a return type for function that doesn't return anything. This will cause a code sample like this:
void foo();
int i = foo();
to generate a compiler error.
2) As the only parameter in a function's parameter list. AFAIK, an empty function's parameter list is exactly the same to the compiler and therefore the following 2 lines are identical in meaning: (edit: it is only true in c++. The comments show the difference in c).
int foo();
int foo(void);
3) void* is a special type of generic pointer- it can point to any variable that is not declared with the const or volatile keyword, convert to/from any type of data pointer, and point to all non-member functions. In addition, it cannot be dereferenced. I will not give examples.
There is also a 4th use that I don't fully understand:
4) In conditional compilation it is often used in the expression (void)0 as following:
// 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
I'm trying to understand the behavior of this expression through experiments. All the following are valid (compile well):
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);
but these are not:
void(0) // no semicolon
int i = void(0);
Can I conclude from this that "void" (in the context of the 4th use) is simply a special type that any type can cast to it (whether it is c-style or cpp-style), and it can never be used as an lvalue or rvalue?
Can I conclude from this that "void" (in the context of the 4th use) is simply a special type that any type can cast to it (whether it is c-style or cpp-style), and it can never be used as an lvalue or rvalue?
James McNellis pointed out in a comment above that void
can be used as an rvalue via the expression void()
.
He quoted this from the current C++ standard:
C++11 §5.2.3/2:
“The expressionT()
, whereT
is a simple-type-specifier or typename-specifier for a non-array complete object type or the (possibly cv-qualified)void
type, creates a prvalue of the specified type, which is value-initialized (no initialization is done for thevoid()
case).”
This makes it possible to write code like …
template< class T >
T foo() { return T(); }
and use foo<void>()
(most likely from other templated code, I would imagine).
Formally void
is just an incomplete type that can never be completed.
As for your 2), in C these:
int foo();
int foo(void);
are not equivalent.
The first is an old-style declaration (still supported in the latest C standard) that says foo
takes a fixed but unspecified number and type of argument(s). A call like foo(42)
doesn't require a diagnostic, but its behavior is undefined unless the definition of foo
says it has a single int
parameter.
The second says specifically that foo
takes no arguments, and foo(42)
requires a diagnostic. The second declaration is a prototype; the first is not. The (void)
syntax was added because some special syntax was needed to be able to declare a parameterless function without writing something that looks like an old-style declaration.
In new C code, you should always use prototypes. Old-style declarations are kept in the language only to support old code.
C++ dropped old-style declarations. In C++, the two declarations of foo
are equivalent; the int foo(void)
form is supported only for compatibility with C.
Your case 4) really has nothing directly to do with conditional compilation. Casting an expression to void
is a way of evaluating the expression and explicitly discarding its value. It's often used to inhibit warnings. For example, if foo()
returns an int
result, then
foo();
as a standalone statement might trigger a warning that you're discarding the result, but
(void)foo();
probably tells the compiler that you intended to do so.
void
is an incomplete type that cannot be completed. That means that an expression of type void
can only be used in a context that doesn't expect a value. And you're right, an expression of type void
cannot be used as an lvalue or rvalue. EDIT: Except in the case Alf described, and only in C++.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With