tags:

views:

395

answers:

7

For the C code below, compare the defintions of the int pointers a and b;

#include <stdio.h>
#include <stdlib.h>

int main()
{
  int *a=malloc(sizeof(int));
  int *b=(int *)malloc(sizeof(int));
  return(0);
}

Is it better in any way to typecast the pointer of type void, returned by the malloc function? Or is it auto-typecasted while assigning to the int pointer on the left hand side? Under which circumstances, if any, can it prove to be necessary rather than just obligatory?

Please clarify whether implicit type casting, where type of right hand side is converted to type of the left hand side, applies here.

+15  A: 

The cast is not needed for the C language, but for C++ compatibility you may want to cast. This is one of the spots where C is not a subset of C++.

The following will compile in C but not C++:

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

The following will compile in both C and C++:

int *b=(int *)malloc(sizeof(int));
Brian R. Bondy
One of the reasons that C++ is more stingent about how pointers are cast is because pointers may change when casting up and down a class hierarchy.
antonm
It is much better to be strict because it will avoid more bugs.
Brian R. Bondy
@Brian. But which way is more "strict"? If you add the cast, and then paste into C++, now a suspicious malloc() line will silently compile, and that may be bad. I believe you *want* the C++ compiler to flag malloc() lines for human attention. "Strict" doesn't have a defined meaning relative to C/C++ but I can see an argument that no cast is more strict.
DigitalRoss
To me, casting malloc in a .c file is a bit like speaking with a foreign accent.
asveikau
+8  A: 

In C the cast is unnecessary. malloc returns a void*, and the C standard states:

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

Further, K&R2 says:

Any pointer to an object may be converted to type void* without loss of information. If the result is converted back to the original pointer type, the original pointer is recovered. Unlike the pointer-to-pointer conversions discussed in Par.A.6.6, which generally require an explicit cast, pointers may be assigned to and from pointers of type void*, and may be compared with them.

A point may be made about C++ compatibility, as in C++ the cast is obligatory. However, IMHO this is hardly relevant, as idiomatic C++ calls for using new instead of malloc anyway.

Eli Bendersky
It is very relevant, for example if you have plans for C++ programs to use your C code.
Brian R. Bondy
@Brian: If your C++ program needs to use your C code it can just _use_ it. Without _porting_ it to C++. So eliben's comment that source code compatibility with C++ isn't a problem is right.
Tomek Szpakowicz
You may for example have code inside a header file that you simply include into your C++ program.
Brian R. Bondy
@Brian: that's what link-time optimizations are for - LLVM has them, and GCC added them recently: http://gcc.gnu.org/wiki/LinkTimeOptimization
Christoph
You may not link at all, but just be re-using the same source files.
Brian R. Bondy
@Brian - But if your code lives in a .c file and your C++ code lives in a .cc/.cxx/.cpp file, there is no issue calling into the C stuff from C++. The real places you have to worry about it are header files. Or people who might copy-paste your code into a C++ file.
asveikau
Not sure about that, I think you can store C++ code into a file that has .c extension and compile it with g++. Also if you include a .h file into a .cpp file you are considering the code as C++ code. In both of those examples you will have compiling errors.
Brian R. Bondy
@Brian: use a C compiler for C code and a C++ compiler for C++ code; the only (valid) reason why you would want to compile C as C++ is to allow header files with inline functions to be includable from both C and C++; with link-time optimizations, it's no longer necessary to define the inline functions in the header as inlining can be done across object files
Christoph
I agree with you all, my point was just that the existence of a problem is possible, not that it is the preferred way.
Brian R. Bondy
@Brian, as I have said elsewhere on this page, (1) most likely C modules will be integrated with C++ still as C, (2) even if you *do* paste or, shudder, **include** those lines into C++, you may want every **malloc** flagged as they are a suspicious thing in C++. Casting **malloc** may very well *complicate* integration of C code into C++ modules.
DigitalRoss
A: 

Is it better in any way to typecast the pointer of type void, returned by the malloc function?

Yes. It is clearer in meaning. It's the same reason I'd write

a = b + (c * d);

Now, I know the "()"s are not needed here, due to the rules of precedence of arithmetic operators, but they help me (and others) clearly see my intent.

$.02, etc. :)

-k

Kevin Little
what do you mean by $.02 etc.?
Kedar Soparkar
0.02 U.S. dollars = 0.924983813 Indian rupees —Google
jleedev
Two cents' worth, a US idiom for "this is only my opinion". One might be said to put one's two cents into the discussion.
David Thornley
+11  A: 

No, Yes, Never

  • Some people cast the pointer, I don't.
  • Yes, the type conversion happens "automatically"
  • It is never necessary in C.
  • In a strange way, casting the result compromises C++ portability. A module referenced from C++ will most likely be compiled as C, in which case it won't matter. But if the code is somehow copy-and-pasted into C++, I think you want each such line flagged, as a line of code calling malloc() in C++ is a suspicious LoC.
  • In part this is a holdover from early K&R C that had no such type as void, so malloc() returned a char *. Now, you needed to do the cast. Consequently the design pattern of casting malloc() developed and influenced all the people who wrote the next set of code, and people are stilling reading those code bodies today and carrying the pattern forward. But C89 had void and so it's time to streamline the code.
  • Depending on exactly how it is done, the cast may violate DRY (aka DIE.) As Chris Lutz points out, it unnecessarily reduces the level of abstraction. Since that isn't exactly sky-high in a C program to start with, I would prefer not to lose the level we do have.
DigitalRoss
Kedar Soparkar
They are correct. My point is merely that you really should give every malloc() line human attention in the unlikely copy-and-paste-into-C++ scenario, so it's *better* to have those lines not just silently compile as if everything was fine.
DigitalRoss
The killer for me is that casting removes the ability to change the type of `c` with minimal effort: in `float *arr = (float *)malloc(10);` we have to change two `float`s to `double` if we need more precision, and what if we had later `realloc()`ed that array and forgot to change the cast there?
Chris Lutz
+3  A: 

If we're talking C, best practice is to not cast the result of malloc(). If we're talking C++, best practice is to use new instead of malloc()1.

The reason I recommend against casting the result is to avoid problems if you forget to #include stdlib.h, or otherwise don't have a prototype for malloc() in scope. Up until C99, if you had a function call with no prior declaration, the compiler would implicitly type the function call to return int. Without the cast, this would result in an incompatible assignment warning. With the cast, the warning is supressed, and runtime errors could possibly result since the value returned from malloc() would be converted from a pointer to an int and back to a pointer again, which is not guaranteed to be meaningful.


  1. If you're porting from C to C++, you might as well convert from malloc() to new up front.
John Bode
+4  A: 

Casting the return value of malloc() is a C++ idiom and has no place in C code. It's only necessary when you want to compile the code as C++, which you shouldn't do as C and C++ are distinct languages with diffrerent semantics.

It only makes sense if you want to make a C library which defines inline functions in header files to be usable from C++. With the advent of link-time optimizations, this hopefully won't be necessary any longer as functions can be inlined even when defined in diffrerent source files.

As to people claiming explicit casting adds to readability, consider the given example

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

How exactly repeating the type THREE TIMES is more readable than

int *b = malloc(sizeof *b);

is beyond me.

C++0x even added type inference to get rid of similar repetitions, so I don't really think this is controversial.

Christoph
+8  A: 

To put it simply:

If you have included stdlib.h, as you should have, then the cast does absolutely nothing, and should be removed. After all, you've specified the type already.

If you have not, then the cast will cover up the error, which is bad.

Never use that cast in C code.

In C++, the cast is necessary, as C++ doesn't permit implicit conversion between void * and other pointer types. On the other hand, in C++ there are better things to use than malloc(), such as new, or container classes.

Writing code that will compile in either is pointless. You should always know what language you're writing in, and writing in the subset forces you to use a construct that's inferior in either language. The C++ compilers I'm familiar with will compile C code as well, and there are explicit provisions in C++ to link easily with C code. If you do compile it as C++, the error message (without the cast) will point out your mistake.

All the cast will do is cover up mistakes that can bite you elsewhere. It won't do anything useful. Don't do it.

David Thornley