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 returnint
.
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 achar *
.- 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 formalloc
is found. In the absence of a prototype formalloc
, the standard requires that the C compiler assumemalloc
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 declaredmalloc
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 atypedef
).
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
How to Implement an Stl-Style Iterator and Avoid Common Pitfalls
Example For Boost Shared_Mutex (Multiple Reads/One Write)
Shared_Ptr to an Array: Should It Be Used
Difference Between Static_Cast≪≫ and C Style Casting
What Should Go into an .H File
What Is an 'Undeclared Identifier' Error and How to Fix It
Calling Delete on Variable Allocated on the Stack
Returning Unique_Ptr from Functions
What Breaking Changes Are Introduced in C++11
When Should Std::Move Be Used on a Function Return Value
How to Print Unicode Character in C++
Sfinae Working in Return Type But Not as Template Parameter
Uninitialized Variable Behaviour in C++