30

In C, there is no need to cast a void * to any other pointer type, it is always safely promoted. However, in C++, this is not the case. E.g.,

int *a = malloc(sizeof(int));

works in C, but not in C++. (Note: I know that you shouldn't use malloc in C++, or for that matter new, and should instead prefer smart pointers and/or the STL; this is asked purely out of curiosity) Why does the C++ standard not allow this implicit cast, while the C standard does?

  • 3
    long *a = malloc(sizeof(int)); Oops, someone forgot to change only one type! – Doval Mar 9 '15 at 14:42
  • 4
    @Doval: That's still easily fixed by using sizeof(*a) instead. – wolfPack88 Mar 9 '15 at 14:46
  • 3
    I believe @ratchetfreak's point is that the reason C does this implicit conversion is because malloc cannot return a pointer to the type allocated. new is C++ does return a pointer to the type allocated, so properly written C++ code will never have any void *s to cast. – Gort the Robot Mar 9 '15 at 15:59
  • 3
    As an aside, it's not any other pointer type. Only data-pointers need apply. – Deduplicator Mar 9 '15 at 16:28
  • 3
    @wolfPack88 you have your history wrong. C++ had void, C did not. When that keyword/idea was added to C, they changed it to suit C's needs. That was shortly after pointer types started being checked at all. See if you can find the K&R C description pamphlet online, or a vintage copy of a C programming text like Waite Group's C Primer. ANSI C was full, of features backported or inspired by C++, and K&R C was much simpler. So it's more correct that C++ extended C as it existed at the time, and the C that you know was stripped down from C++. – JDługosz Mar 9 '15 at 19:02
39

Because implicit type conversions are usually unsafe, and C++ takes a more safe stance to typing than C does.

C will usually allow implicit conversions, even if most chances are that the conversion is an error. That's because C assumes that the programmer knows exactly what they are doing, and if not, it is the programmer's problem, not the compiler's problem.

C++ will usually disallow things that could potentially be errors, and require you to explicitly state your intention with a type cast. That's because C++ is trying to be programmer-friendly.

You might ask how come it is friendly when it is actually requiring you to type more.

Well, you see, any given line of code, in any program, in any programming language, will generally be read many more times than it will be written (*). So, ease of reading is much more important than ease of writing. And when reading, having any potentially unsafe conversions stand out by means of explicit type casts helps to understand what is going on and to have a certain level of certainty that what is happening is in fact what was intended to happen.

Besides, the inconvenience of having to type the explicit cast is trivial compared to the inconvenience of hours upon hours of troubleshooting to find a bug which was caused by a mistaken assignment that you could have been warned about, but never were.

(*) Ideally it will be written only once, but it will be read every time someone needs to review it to determine its suitability for reuse, and every time there is troubleshooting going on, and every time someone needs to add code near it, and then every time there is troubleshooting of nearby code, and so on. This is true in all cases except for "write-once, run, then throw away" scripts, and so it is no wonder that most scripting languages have a syntax which facilitates ease of writing with complete disregard to ease of reading. Ever thought that perl is completely incomprehensible? You are not alone. Think of such languages as "write-only" languages.

| improve this answer | |
  • C is essentially one step above machine code. I can pardon C for things like this. – Qix - MONICA WAS MISTREATED Mar 9 '15 at 18:18
  • 8
    Programs (whatever the language) are meant to be read. Explicit operations stand out. – Matthieu M. Mar 9 '15 at 18:50
  • 10
    It's worth noting, that casts through void* are more unsafe in C++, because with the way certain OOP features are implemented in C++, pointer to same object might have different value depending on pointer type. – hyde Mar 9 '15 at 19:50
  • @MatthieuM. very true. Thanks for adding that, it is worth being part of the answer. – Mike Nakis Mar 10 '15 at 9:53
  • 1
    @MatthieuM.: Ah, but you really don't want to have to do everything explicitly. Readability is not enhanced by having more to read. Though in this point the balance is clearly for being explicit. – Deduplicator Mar 10 '15 at 16:39
28

Here is what Stroustrup says:

In C, you can implicitly convert a void* to a T*. This is unsafe

He then goes on to show an example of how void* can be dangerous and says:

... Consequently, in C++, to get a T* from a void* you need an explicit cast. ...

Finally, he notes:

One of the most common uses of this unsafe conversion in C is to assign the result of malloc() to a suitable pointer. For example:

int* p = malloc(sizeof(int));

In C++, use the typesafe new operator:

int* p = new int;

He goes into a lot more detail on this in The Design and Evolution of C++.

So the answer boils down to: The language designer believes it is an unsafe pattern, and so made it illegal and provided alternate ways of accomplishing what the pattern was normally used for.

| improve this answer | |
  • 1
    Relating to the malloc example, it's worth noting that malloc will (obviously) not call a constructor, so if it is a class type you are allocating memory for, being able to implicitly cast to the class type would be misleading. – chbaker0 Mar 9 '15 at 23:37
  • This is a very good answer, arguably better than mine. I only slightly dislike the "argument from authority" approach. – Mike Nakis Mar 10 '15 at 9:52
  • "new int" - wow, as a C++ newbie I was having trouble thinking of a way to add a base type to the heap, and I didn't even know you could do that. -1 use for malloc. – Katana314 Mar 10 '15 at 13:57
  • 3
    @MikeNakisFWIW, my intent was to complement your answer. In this case, the question was "why did they do that", so I figured hearing from the chief designer is justified. – Gort the Robot Mar 10 '15 at 15:49
11

In C, there is no need to cast a void * to any other pointer type, it is always safely promoted.

It's always promoted, yes, but hardly safely.

C++ disables this behaviour precisely because it attempts to have a safer type system than C, and this behaviour is not safe.


Consider in general these 3 approaches to type conversion:

  1. force the user to write everything out, so all conversions are explicit
  2. assume the user knows what they're doing and convert any type to any other
  3. implement a complete type system with type-safe generics (templates, new-expressions), explicit user-defined conversion operators, and force explicit conversions only of things the compiler can't see are implicitly safe

Well, 1 is ugly and a practical obstacle to getting anything done, but might genuinely be used where great care is needed. C roughly opted for 2, which is easier to implement, and C++ for 3, which is harder to implement but safer.

| improve this answer | |
  • It was a long hard road to get to 3, with exceptions added later and templates later still. – JDługosz Mar 9 '15 at 19:06
  • Well, templates aren't really needed for such a complete safe type system: Hindley-Milner based languages get along without them quite well, without implicit conversions at all and no need to write out types explictly either. (Of course, these languages rely on type erasure / garbage collection / higher-kinded polymorphism, things which C++ rather avoids.) – leftaroundabout Mar 10 '15 at 0:48
1

By definition, A void pointer can point to anything. Any pointer can be converted to a void pointer and thus, you will be able to convert back arriving at the exact same value. However, pointers to other types may have constraints, such as alignment restrictions. For example, imagine an architecture where characters can occupy any memory address but integers must start on even address boundaries. In certain architectures, integer pointers might even count 16, 32 or 64 bits at a time so that a char * might actually have a multiple of the numeric value of int * while pointing to the same place in memory. In this case, converting from a void * actually would round off bits which can not be recovered and is therefore not reversible.

Put simply, the void pointer can point to anything, including things that other pointers may not be capable of pointing to. Thus, the conversion to the void pointer is safe but not the other way around.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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