Now before people start marking this a dup, I've read all the following, none of which provide the answer I'm looking for:
Both the C FAQ and many answers to the above questions cite a mysterious error that casting malloc
's return value can hide; however, none of them give a specific example of such an error in practice. Now pay attention that I said error, not warning.
Now given the following code:
#include <string.h> #include <stdio.h> // #include <stdlib.h> int main(int argc, char** argv) { char * p = /*(char*)*/malloc(10); strcpy(p, "hello"); printf("%s\n", p); return 0; }
Compiling the above code with gcc 4.2, with and without the cast gives the same warnings, and the program executes properly and provides the same results in both cases.
anon@anon:~/$ gcc -Wextra nostdlib_malloc.c -o nostdlib_malloc nostdlib_malloc.c: In function ‘main’: nostdlib_malloc.c:7: warning: incompatible implicit declaration of built-in function ‘malloc’ anon@anon:~/$ ./nostdlib_malloc hello
So can anyone give a specific code example of a compile or runtime error that could occur because of casting malloc
's return value, or is this just an urban legend?
Edit I've come across two well written arguments regarding this issue:
In C, you don't need to cast the return value of malloc . The pointer to void returned by malloc is automagically converted to the correct type. However, if you want your code to compile with a C++ compiler, a cast is needed.
Type casting refers to changing an variable of one data type into another. The compiler will automatically change one type of data into another if it makes sense. For instance, if you assign an integer value to a floating-point variable, the compiler will convert the int to a float.
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 .
This type of typecasting is essential when you want to change data types without changing the significance of the values stored inside the variable. Implicit type conversion in C happens automatically when a value is copied to its compatible data type. During conversion, strict rules for type conversion are applied.
You won't get a compiler error, but a compiler warning. As the sources you cite say (especially the first one), you can get an unpredictable runtime error when using the cast without including stdlib.h
.
So the error on your side is not the cast, but forgetting to include stdlib.h
. Compilers may assume that malloc
is a function returning int
, therefore converting the void*
pointer actually returned by malloc
to int
and then to your pointer type due to the explicit cast. On some platforms, int
and pointers may take up different numbers of bytes, so the type conversions may lead to data corruption.
Fortunately, modern compilers give warnings that point to your actual error. See the gcc
output you supplied: It warns you that the implicit declaration (int malloc(int)
) is incompatible to the built-in malloc
. So gcc
seems to know malloc
even without stdlib.h
.
Leaving out the cast to prevent this error is mostly the same reasoning as writing
if (0 == my_var)
instead of
if (my_var == 0)
since the latter could lead to a serious bug if one would confuse =
and ==
, whereas the first one would lead to a compile error. I personally prefer the latter style since it better reflects my intention and I don't tend to do this mistake.
The same is true for casting the value returned by malloc
: I prefer being explicit in programming and I generally double-check to include the header files for all functions I use.
One of the good higher-level arguments against casting the result of malloc
is often left unmentioned, even though, in my opinion, it is more important than the well-known lower-level issues (like truncating the pointer when the declaration is missing).
A good programming practice is to write code, which is as type-independent as possible. This means, in particular, that type names should be mentioned in the code as little as possible or best not mentioned at all. This applies to casts (avoid unnecessary casts), types as arguments of sizeof
(avoid using type names in sizeof
) and, generally, all other references to type names.
Type names belong in declarations. As much as possible, type names should be restricted to declarations and only to declarations.
From this point of view, this bit of code is bad
int *p; ... p = (int*) malloc(n * sizeof(int));
and this is much better
int *p; ... p = malloc(n * sizeof *p);
not simply because it "doesn't cast the result of malloc
", but rather because it is type-independent (or type-agnositic, if you prefer), because it automatically adjusts itself to whatever type p
is declared with, without requiring any intervention from the user.
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