27

In strongly-typed languages like Java and C#, void (or Void) as a return type for a method seem to mean:

This method doesn't return anything. Nothing. No return. You will not receive anything from this method.

What's really strange is that in C, void as a return type or even as a method parameter type means:

It could really be anything. You'd have to read the source code to find out. Good luck. If it's a pointer, you should really know what you're doing.

Consider the following examples in C:

void describe(void *thing)
{
    Object *obj = thing;
    printf("%s.\n", obj->description);
}

void *move(void *location, Direction direction)
{
    void *next = NULL;

    // logic!

    return next;
}

Obviously, the second method returns a pointer, which by definition could be anything.

Since C is older than Java and C#, why did these languages adopt void as meaning "nothing" while C used it as "nothing or anything (when a pointer)"?

12
  • 141
    Your question title and text talks about void while the code example uses void* which is something completely different.
    – user22815
    Aug 22, 2014 at 20:50
  • 4
    Also note that Java and C# do have the same concept, they simply call it Object in one case to disambiguate. Aug 23, 2014 at 0:31
  • 4
    @Mephy they aren't exactly strongly-typed? By C# using duck typing, do you mean the dynamic type that is rarely used?
    – Axarydax
    Aug 23, 2014 at 7:29
  • 9
    @Mephy: Last time I checked Wikipedia listed eleven mutually contradictory meanings for "strongly-typed". Saying that "C# is not strongly typed" is therefore meaningless. Aug 23, 2014 at 17:25
  • 8
    @LightnessRacesinOrbit: No, the point is that there is no authoritative definition of the term. Wikipedia is not a prescriptive resource that tells you what the right meaning of a term is. It is a descriptive resource. The fact that it describes eleven different contradictory meanings is evidence that the term cannot be used in conversation without carefully defining it. Doing otherwise means that odds are very good the people in the conversation will be talking past, not to, each other. Aug 24, 2014 at 18:30

11 Answers 11

61

The keyword void (not a pointer) means "nothing" in those languages. This is consistent.

As you noted, void* means "pointer to anything" in languages that support raw pointers (C and C++). This is an unfortunate decision because as you mentioned, it does make void mean two different things.

I have not been able to find the historical reason behind reusing void to mean "nothing" and "anything" in different contexts, however C does this in several other places. For example, static has different purposes in different contexts. There is obviously precedent in the C language for reusing keywords this way, regardless of what one may think of the practice.

Java and C# are different enough to make a clean break to correct some of these issues. Java and "safe" C# also do not allow raw pointers and do not need easy C compatibility (Unsafe C# does allow pointers but the vast majority of C# code does not fall into this category). This allows them to change things up a bit without worrying about backwards compatibility. One way of doing this is introducing a class Object at the root of the hierarchy from which all classes inherit, so an Object reference serves the same function of void* without the nastiness of type issues and raw memory management.

14
  • 2
    I'll provide a reference when I get home
    – user22815
    Aug 22, 2014 at 21:11
  • 4
    They also do not allow raw pointers and do not need easy C compatibility. False. C# has pointers. They're usually (and usually should be) off, but they're there.
    – Magus
    Aug 22, 2014 at 23:05
  • 8
    Regarding why they reused void: an obvious reason would be to avoid introducing a new keyword (and potentially breaking existing programs). Had they introduced a special keyword (e.g. unknown), then void* would be a meaningless (and possibly illegal) construct, and unknown would be legal only in the form of unknown*.
    – jamesdlin
    Aug 23, 2014 at 2:55
  • 21
    Even in void *, void means "nothing", not "anything". You can't dereference a void *, you need to cast it first to another pointer type.
    – oefe
    Aug 23, 2014 at 8:27
  • 3
    @Snowman: Your most recent comment is a much better description of what void is than your answer: It is, literally, the absence of type. Simple as that. And, having no type, it can have no value; so a type of pointer to void is a pointer to nothing in particular, just a location in memory.
    – greyfade
    Aug 24, 2014 at 18:31
33

void and void* are two different things. void in C means exactly the same thing as it does in Java, an absence of a return value. A void* is a pointer with an absence of a type.

All pointers in C need to be able to be dereferenced. If you dereferenced a void*, what type would you expect to get? Remember C pointers don't carry any runtime type information, so the type must be known at compile time.

Given that context, the only thing you can logically do with a dereferenced void* is ignore it, which is exactly the behavior the void type denotes.

5
  • 1
    I agree until you get to the "ignore it" bit. It is possible that the thing returned contains information about how to interpret it. In other words, it could be the C equivalent of a BASIC Variant. "When you get this, take a look to figure out what it is - I can't tell you up front what you will find".
    – Floris
    Aug 23, 2014 at 12:50
  • 1
    Or to put it another way, hypothetically I could put a programmer-defined "type descriptor" in the first byte at the memory location addressed by the pointer, which would tell me what data type I can expect to find in the bytes that follow. Aug 23, 2014 at 18:02
  • 1
    Of course, but in C it was decided to leave those details up to the programmer, rather than bake them into the language. From the language point of view, it doesn't know what else to do other than ignore. This avoids the overhead of always including type information as the first byte when in most use cases you can determine it statically. Aug 23, 2014 at 21:20
  • 4
    @RobertHarvey yes, but then you're not dereferencing a void pointer; you're casting the void pointer to a char pointer and then dereferencing the char pointer.
    – user253751
    Aug 24, 2014 at 5:50
  • 4
    @Floris gcc disagree with you. If you try to use the value, gcc produce an error message saying error: void value not ignored as it ought to be.
    – kasperd
    Aug 24, 2014 at 9:33
19

Perhaps it would be more useful to think of void as the return type. Then your second method would read "a method that returns an untyped pointer."

3
  • That helps. As someone who is (finally!) learning C after years spent in object-oriented languages, pointers are something that is a very new concept to me. It seems that when returning a pointer, void is roughly an equivalent to * of languages like ActionScript 3 which simply means "any return type." Aug 22, 2014 at 20:37
  • 5
    Well, void is not a wildcard. A pointer is just a memory address. Putting a type before the * says "here is the data type you can expect to find at the memory address referred to by this pointer." Putting void before the * says to the compiler "I don't know the type; just return me the raw pointer, and I'll figure out what to do with the data that it points to." Aug 22, 2014 at 20:40
  • 2
    I would even say that a void* points at a "void". A bare pointer with nothing it points at. Still you can cast it like any other pointer.
    – Robert
    Aug 23, 2014 at 21:09
11

Let's tighten up the terminology a bit.

From the online C 2011 standard:

6.2.5 Types
...
19 The void type comprises an empty set of values; it is an incomplete object type that cannot be completed.
...
6.3 Conversions
...
6.3.2.2 void

1 The (nonexistent) value of a void expression (an expression that has type void) shall not be used in any way, and implicit or explicit conversions (except to void) shall not be applied to such an expression. If an expression of any other type is evaluated as a void expression, its value or designator is discarded. (A void expression is evaluated for its side effects.)

6.3.2.3 Pointers

1 A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.

A void expression has no value (although it may have side effects). If I have a function defined to return void, like so:

void foo( void ) { ... }

then the call

foo();

doesn't evaluate to a value; I can't assign the result to anything, because there is no result.

A pointer to void is essentially a "generic" pointer type; you can assign a value of void * to any other object pointer type without needing an explicit cast (which is why all the C programmers will yell at you for casting the result of malloc).

You cannot directly dereference a void *; you must first assign it to a different object pointer type before you can access the pointed-to object.

void pointers are used to implement (more-or-less) generic interfaces; the canonical example is the qsort library function, which can sort arrays of any type, as long as you provide a type-aware comparison function.

Yes, using the same keyword for two different concepts (no value vs. generic pointer) is confusing, but it's not like there isn't precedent; static has multiple distinct meanings in both C and C++.

9

In Java and C#, void as a return type for a method seem to mean: this method doesn't return anything. Nothing. No return. You will not receive anything from this method.

That statement is correct. It is correct for C and C++ as well.

in C, void as a return type or even as a method parameter type means something different.

That statement is incorrect. void as a return type in C or C++ means the same thing that it does in C# and Java. You are confusing void with void*. They are completely different.

Isn't it confusing that void and void* mean two completely different things?

Yep.

What is a pointer? What is a void pointer?

A pointer is a value which may be dereferenced. Dereferencing a valid pointer gives a storage location of the pointed-to type. A void pointer is a pointer which has no particular pointed-to type; it must be converted to a more specific pointer type before the value is dereferenced to produce a storage location.

Are void pointers the same in C, C++, Java and C#?

Java does not have void pointers; C# does. They are the same as in C and C++ -- a pointer value which does not have any specific type associated with it, that must be converted to a more specific type before dereferencing it to produce a storage location.

Since C is older than Java and C#, why did these languages adopt void as meaning "nothing" while C used it as "nothing or anything (when a pointer)"?

The question is incoherent because it presupposes falsehoods. Let's ask some better questions.

Why did Java and C# adopt the convention that void is a valid return type, instead of, for instance, using the Visual Basic convention that functions are never void returning and subroutines are always void returning?

To be familiar to programmers coming to Java or C# from languages where void is a return type.

Why did C# adopt the confusing convention that void* has a completely different meaning than void ?

To be familiar to programmers coming to C# from languages where void* is a pointer type.

5
void describe(void *thing);
void *move(void *location, Direction direction);

The first function returns nothing. The second function returns a void pointer. I would have declared that second function as

void* move(void* location, Direction direction);

If might help if you think of "void" as meaning "without meaning". The return value of describe is "without meaning". Returning a value from such a function is illegal because you told the compiler that the return value is without meaning. You can't capture the return value from that function because it is without meaning. You can't declare a variable of type void because it is without meaning. For example void nonsense; is nonsense and is in fact illegal. Also note that an array of void void void_array[42]; is also nonsense.

A pointer to void (void*) is something different. It is a pointer, not an array. Read void* as meaning a pointer that points to something "without meaning". The pointer is "without meaning", which means it doesn't make sense to dereference such a pointer. Trying to do so is in fact illegal. Code that dereferences a void pointer won't compile.

So if you can't dereference a void pointer, and you can't make an array of voids, how can you use them? The answer is that a pointer to any type can be cast to and from void*. Casting some pointer to void* and casting back to a pointer to the original type will yield a value equal to the original pointer. The C standard guarantees this behavior. The primary reason you see so many void pointers in C is that this capability provides a way to implement information hiding and object-based programming in what is very much a non-object oriented language.

Finally, the reason you often see move declared as void *move(...) rather than void* move(...) is because putting the asterisk next to the name rather than the type is a very common practice in C. The reason is that the following declaration will get you in big trouble: int* iptr, jptr; This would make you think you are declaring two pointers to an int. You are not. This declaration makes jptr an int rather than a pointer to an int. The proper declaration is int *iptr, *jptr; You can pretend the asterisk belongs with the type if you stick to the practice of only declaring one variable per declaration statement. But keep in mind that you are pretending.

2
  • "Code that dereferences a null pointer won't compile." I think you mean code that dereferences a void pointer won't compile. The compiler doesn't protect you from dereferencing a null pointer; that is a runtime problem. Aug 23, 2014 at 8:47
  • @CodyGray - Thanks! Fixed that. Code that dereferences a null pointer will compile (so long as the pointer is not void* null_ptr = 0;). Aug 23, 2014 at 10:04
2

Simply put, there is no difference. Let me give you some examples.

Say I have an class called Car.

Car obj = anotherCar; // obj is now of type Car
Car* obj = new Car(); // obj is now a pointer of type Car
void obj = 0; // obj has no type
void* = new Car(); // obj is a pointer with no type

I believe here the confusion here is based off how you would define void vs void*. A return-type of void means "I return nothing", while a return type of void* means "I return a pointer of type nothing".

This is due to the fact that a pointer is a special case. A pointer object will always point to a location in memory, whether there's a valid object there or not. Whether my void* car references a byte, a word, a Car, or a bicycle doesn't matter because my void* points to something with no defined type. It's up to us to later on define it.

In languages such as C# and Java, memory is managed and the concept of pointers is rolled over into the Object class. Instead of having a reference to an object of type "nothing" we know that at the very least our object is of type "Object". Let me explain why.

In conventional C/C++ if you create an object and delete its pointer, then it's impossible to get access to that object. This is what's known as a memory leak.

In C#/Java, everything is an object and this enables the runtime to keep track of every object. It doesn't necessarily need to know that my object is a Car, it simply needs to know some basic information that is already taken care of by the Object class.

For us programmers, that means that much of the information we would have to manually take care of in C/C++ is taken care of for us by the Object class, removing the need for the special case that is the pointer.

1
  • "my void* points to something with no defined type" - not exactly. It's more correct to say it's a pointer to a zero-length value (almost like an array with 0 elements, but without even the type information associated with the array). Aug 25, 2014 at 15:00
2

I'll try to say how one could think of these things in C. The official language in the C standard is not really at ease with void, and I won't try to be entirely consistent with it.

The type void is not a first class citizen among the types. Although it is an object type, it cannot be the type of any object (or value), of a field, or of a function parameter; however it can be the return type of a function, and thereby be the type of an expression (basically of calls of such functions, but expressions formed with the conditional operator can also have void type). But even the minimal use of void as a value type that the above leaves the door open for, namely ending a function returning void with a statement of the form return E; where E is an expression of type void, is explicitly forbidden in C (it is allowed in C++ though, but for reasons not applicable to C).

If objects of type void were allowed, they would have 0 bits (that is the amount of information in the value of an expression of void type); it would not be a major problem allowing such objects, but they would be rather useless (objects of size 0 would give some difficulty with defining pointer arithmetic, which would maybe best just be forbidden). The set of different values such an object would have one (trivial) element; its value could be taken, trivially because it does not have any substance, but it cannot be modified (lacking any different value). The standard is therefore confused in saying void comprises an empty set of values; such a type could be useful to describe expressions that cannot be evaluated (such as jumps or non-terminating calls) although the C language does not actually employ such a type.

Being disallowed as value type, void has been used in at least two not directly related ways to designate "forbidden": specifying (void) as parameter specification in function types means providing any arguments to them is forbidden (while '()' would to the contrary mean everything is allowed; and yes, even providing a void expression as argument to functions with (void) parameter specification is forbidden), and declaring void *p means that the dereferencing expression *p is forbidden (but not that it is a valid expression of type void). So you are right that these uses of void are not really consistent with void as a valid type of expressions. However an object of type void* is not really a pointer to values of any type, it means a value that is treated as a pointer although it cannot be dereferenced and pointer arithmetic with it is forbidden. The "treated as a pointer" then really only means it can be cast from and to any pointer type without loss of information. However it can also be used to cast integer values to and from, so it does not have to point to anything at all.

1
  • Strictly speaking, it can be cast from and to any object pointer type without loss of information but not always to and from. In general a cast from void* to another pointer type might lose information (or even have UB, I can't remember off hand), but if the value of the void* came from casting a pointer of the same type you're now casting to, then it doesn't. Aug 24, 2014 at 14:16
0

In C# and Java, every class is derived from an Object class. Hence whenever we wish to pass a reference to "something", we can use a reference of type Object.

Since we don't need to use void pointers for that purpose in these languages, void doesn't have to mean "something or nothing" here.

0

In C, it is possible to have a pointer to things of any type [pointers behave as a type of reference]. A pointer may identify an object of a known type, or it may identify an object of arbitrary (unknown) type. The creators of C chose to use the same general syntax for "pointer to thing of arbitrary type" as for "pointer to thing of some particular type". Since the syntax in the latter case requires a token to specify what the type is, the former syntax requires putting something where that token would belong if the type were known. C chose to use the keyword "void" for that purpose.

In Pascal, as with C, it is possible to have pointers to things of any type; more popular dialects of Pascal also allow "pointer to thing of arbitrary type", but rather than using the same syntax as they use for "pointer to thing of some particular type", they simply refer to the former as Pointer.

In Java, there are no user-defined variable types; everything is either a primitive or a heap object reference. One can define things of type "reference to a heap object of a particular type" or "reference to a heap object of arbitrary type". The former simply uses the type name without any special punctuation to indicate that it's a reference (since it can't be anything else); the latter uses the type name Object.

The use of void* as the nomenclature for a pointer to something of arbitrary type is so far as I know unique to C and direct derivatives like C++; other languages I know of handle the concept by simply using a distinctly-named type.

-1

You can kind of think of the keyword void like an empty struct (In C99 empty structs are apparently disallowed, in .NET and C++ they take up more than 0 memory, and last I recall everything in Java is a class):

struct void {
};

...which means it's a type with 0 length. This is how it's working when you do a function call that returns void... instead of allocating 4 bytes or so on the stack for an integer return value, it doesn't change the stack pointer at all (increments it by a length of 0).

So, if you declared some variables like:

int a;
void b;
int c;

... and then you took the address of those variables, then perhaps b and c might be located at the same place in memory, because b has zero length. So a void* is a pointer in memory to the built-in type with zero length. The fact that you might know that there's something immediately after it that might be useful to you is another matter, and requires you to really know what you're doing (and is dangerous).

1
  • The only compiler that I know of that assigns a length to type void is gcc, and gcc assigns it a length of 1.
    – Joshua
    Sep 12, 2017 at 16:41

Not the answer you're looking for? Browse other questions tagged or ask your own question.