Is it a better practice to typecast the pointer re

2019-01-19 23:09发布

问题:

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.

回答1:

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));


回答2:

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.


回答3:

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.



回答4:

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.



回答5:

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.



回答6:

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.


回答7:

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