Why Does C++ Require a Cast For Malloc() But C Doesn'T

Why does C++ require a cast for malloc() but C doesn't?

Several points:

C allows void pointers to be implicitly converted to any other object pointer type. C++ does not.

Casting the result of malloc() in C will supress a useful diagnostic if you forget to include stdlib.h or otherwise don't have a declaration for malloc() in scope. Remember that if C sees a function call without a prior declaration, it will assume that the function returns int. If you don't have a declaration for malloc() and you leave off the cast, you'll get a diagnostic to the effect that you're trying to assign incompatible types (int to pointer). If you cast the result, you supress the diagnostic and will potentially have runtime issues, since it's not guaranteed that converting a pointer value to an int and back to a pointer again will give you a useful result.

If you're writing C++, you should be using new and delete instead of malloc() and free(). Yeah, yeah, yeah, I've heard all the reasons why people want their code to compile as both C and C++, but the benefits of using the right memory management tool for the language outweigh the cost of maintaining two versions IMO.

Note: the void * type was added in the C89 standard; earlier versions of C had malloc() return char *, so in those versions the cast was required if you were assigning the result to a different pointer type. Almost everybody supports at least the C89 standard though, so the odds of you running into one of those older implementations is very, very low.

Do I cast the result of malloc?

TL;DR

int *sieve = (int *) malloc(sizeof(int) * length);

has two problems. The cast and that you're using the type instead of variable as argument for sizeof. Instead, do like this:

int *sieve = malloc(sizeof *sieve * length);

Long version

No; you don't cast the result, since:

  • It is unnecessary, as void * is automatically and safely promoted to any other pointer type in this case.
  • It adds clutter to the code, casts are not very easy to read (especially if the pointer type is long).
  • It makes you repeat yourself, which is generally bad.
  • It can hide an error if you forgot to include <stdlib.h>. This can cause crashes (or, worse, not cause a crash until way later in some totally different part of the code). Consider what happens if pointers and integers are differently sized; then you're hiding a warning by casting and might lose bits of your returned address. Note: as of C99 implicit functions are gone from C, and this point is no longer relevant since there's no automatic assumption that undeclared functions return int.

As a clarification, note that I said "you don't cast", not "you don't need to cast". In my opinion, it's a failure to include the cast, even if you got it right. There are simply no benefits to doing it, but a bunch of potential risks, and including the cast indicates that you don't know about the risks.

Also note, as commentators point out, that the above talks about straight C, not C++. I very firmly believe in C and C++ as separate languages.

To add further, your code needlessly repeats the type information (int) which can cause errors. It's better to de-reference the pointer being used to store the return value, to "lock" the two together:

int *sieve = malloc(length * sizeof *sieve);

This also moves the length to the front for increased visibility, and drops the redundant parentheses with sizeof; they are only needed when the argument is a type name. Many people seem to not know (or ignore) this, which makes their code more verbose. Remember: sizeof is not a function! :)


While moving length to the front may increase visibility in some rare cases, one should also pay attention that in the general case, it should be better to write the expression as:

int *sieve = malloc(sizeof *sieve * length);

Since keeping the sizeof first, in this case, ensures multiplication is done with at least size_t math.

Compare: malloc(sizeof *sieve * length * width) vs. malloc(length * width * sizeof *sieve) the second may overflow the length * width when width and length are smaller types than size_t.

Why does the type cast of malloc in C have the * symbol on the right and not on the left?

That's because when declaring a pointer the "*" is on the left, not on the right.

The * is on the right of the type name. In void *p = &a; type is void *, a void pointer. It is on the left of the thing it's being applied to, the variable p.

In ptr = (cast-type*) malloc(byte-size) the type is cast-type *, the * is to the right of the type name. The cast is on the left of the thing being cast, the call to malloc, like an adjective.

[I do find it odd that we write type *variable, which makes it seem like the * is part of the variable rather than type* variable which puts the * with the type.]

Why do we cast return value of malloc?

No need to cast return value of malloc as its return type is void*.

Can someone explain why do some programmers use (char *) in front of the malloc?

They are doing wrong (most probably) by casting it (in good programmers opinion).

As wiki says:

malloc returns a void pointer (void *), which indicates that it is a pointer to a region of unknown data type. The use of casting is required in C++ due to the strong type system, whereas this is not the case in C1. The lack of a specific pointer type returned from malloc is type-unsafe behavior according to some programmers: malloc allocates based on byte count but not on type. This is different from the C++ new operator that returns a pointer whose type relies on the operand.
One may "cast" this pointer to a specific type:

int *ptr;
ptr = malloc(10 * sizeof (*ptr)); /* without a cast */
ptr = (int *)malloc(10 * sizeof (*ptr)); /* with a cast */
ptr = reinterpret_cast<int *>(malloc(10 * sizeof (*ptr))); /* with a cast, for C++ */

There are advantages and disadvantages to performing such a cast.

Advantages to casting:

  • Including the cast allows a program or function to compile as C++.
  • The cast allows for pre-1989 versions of malloc that originally returned a char *.
  • Casting can help the developer identify inconsistencies in type sizing should the destination pointer type change, particularly if the pointer is declared far from the malloc() call.

Disadvantages to casting:

  • Under the ANSI C standard, the cast is redundant.
  • Adding the cast may mask failure to include the header stdlib.h, in which the prototype for malloc is found. In the absence of a prototype for malloc, the standard requires that the C compiler assume malloc returns an int. If there is no cast, a warning is issued when this integer is assigned to the pointer; however, with the cast, this warning is not produced, hiding a bug. On certain architectures and data models (such as LP64 on 64-bit systems, where long and pointers are 64-bit and int is 32-bit), this error can actually result in undefined behavior, as the implicitly declared malloc returns a 32-bit value whereas the actually defined function returns a 64-bit value. Depending on calling conventions and memory layout, this may result in stack smashing. This issue is less likely to go unnoticed in modern compilers, as they uniformly produce warnings that an undeclared function has been used, so a warning will still appear. For example, GCC's default behavior is to show a warning that reads "incompatible implicit declaration of built-in function" regardless of whether the cast is present or not.
  • If the type of the pointer is changed, one must fix all code lines where malloc was called and cast (unless it was cast to a typedef).

1. Emphases are mine.

Why does writing pointer type in front of malloc function in C++ language?

C and C++ are two different languages each with their own set of rules.

In both C and C++ malloc returns a void*.

In C a void* is compatible with any pointer so it can (and should) be assigned directly. In C++ it is not compatible with anything else so it cannot be assigned directly to a non void*.

So if you want to use malloc in C++ (you should not) you have to cast the void* return value to the appropriate pointer type, int* in your example.



Related Topics



Leave a reply



Submit