I was just reading about the bad practice of casting the return value of malloc
. If I understood correctly, it is absolutely legal to leave the cast as it is do
The reason you don't cast the return value of malloc
is because you are always assigning the return value to a pointer type, and the C standard allows a void *
to be implicitly cast to any other pointer type. Explicitly casting it is redundant, and therefore unnecessary.
If and when you need to cast I always suggest you do this explicitly to show others, or perhaps yourself in the future, that you intended for this behavior.
By the way, the gcc warning for this is -Wconversion
. Unfortunately -Wall and -Wextra still leave alot of good warnings off.
Here are the flags I use when I want gcc to be very lint-like
-pedantic -std=c99 -ggdb3 -O0 -Wall -Wextra -Wformat=2 -Wmissing-include-dirs -Winit-self -Wswitch-default -Wswitch-enum -Wunused-parameter -Wfloat-equal -Wundef -Wshadow -Wlarger-than-1000 -Wunsafe-loop-optimizations -Wbad-function-cast -Wcast-qual -Wcast-align -Wconversion -Wlogical-op -Waggregate-return -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-declarations -Wpacked -Wpadded -Wredundant-decls -Wnested-externs -Wunreachable-code -Winline -Winvalid-pch -Wvolatile-register-var -Wstrict-aliasing=2 -Wstrict-overflow=2 -Wtraditional-conversion -Wwrite-strings
I also check my code first with cppcheck which is a free static code analyzer for C and C++. Highly recommended.
There are at least two kinds of casts:
Casts of numeric values that cause a change of representation. (This is a term of art you will find in Harbison and Steele's very helpful C Reference Manual.) These casts are mostly innocuous; the only way you can do harm is by, e.g., casting a wider type to a narrower type, in which case you are deliberately throwing away bits. Only you, the programmer, know whether it's safe to throw away those bits.
C also has an insidious feature that it may perform a change of representation on your behalf when you assign, return, or pass a numeric expression whose type doesn't exactly match the type of the associate lvalue, result, or argument. I think this feature is pernicious, but it is firmly embedded in the C way of doing things. The gcc
option -Wconversion
will let you know where the compiler is doing a change of representation on your behalf, without being asked.
Casts that don't involve a change of representation but simply ask the compiler to view bits a certain way. These include casts between signed and unsigned types of the same size, as well as casts between pointer types that point to different sorts of data. The type void *
enjoys a special status in C as the compiler will convert freely between void *
and other data pointer types without a cast. Note that a cast between pointers of two different types of data never involves a change of representation. This is one reason the void *
convention can work.
One reason C programmers try to avoid gratuitous casts is that when you write a cast, the compiler trusts you completely. If you make a mistake, the compiler is not going to catch it for you. For this reason I advise my student never to cast pointer types unless they know exactly what they are doing.
P.S. I thought it would be possible to write a short, helpful answer to this question. Wrong!
My simple guideline - if it needs a cast, it's probably wrong. If you don't need a cast, don't use them.
You can't ask about casting in 'C' w/o understanding that casting covers more than one type of operation. There are essentially two, type conversion and type coercion. In C++, because it has more type info, it's creating 4 types of casts and codified this with an exclusive notation. reinterpret_cast<>
, const_cast<>
, dynamic_cast<>
and static_cast<>
. You don't have these in C since all casts have the syntax (ctype)
but the reasons for them remain and it helps to understand why casting is required even though your question was about 'C' specifically.
The "need" for static cast is what you show in your example. The compiler will do them for you, even if you don't specify it - however, crank the warning level up high enough, and the compiler will warn you if there is a loss of precision as there is going from double to float (your return bar;
statement). Adding a cast tells the compiler the loss of precision was intended.
The second least dangerous cast is a const cast<>. It's used to removed const or volatile from a type. This commonly occurs where structures have internal "caches". So a caller may have a const version of your structure, but an "internal function" needs to update the cache so will have to cast from a pointer to a const struct to a regular struct to update an internal field.
The most dangerous type is a reinterpret cast and why people will go on and on about how bad it is to cast. That's where you're not converting anything, but telling the compiler to reinterpret a value as a totally different type. What is below might have been added by a naive programmer trying to get rid of a compiler error.
char **ptostr = (char **p) "this is not a good idea";
Likely the correct fix was to use an '&' and this is how casting gets a bad reputation. Casts like this can be used for good or evil. I used it in the answer to another question about how to find the smallest power of 2 in order to leverage the power of the FPU in a CPU. A better example of being used for good, is when implementing linked lists. If the links live in the objects themselves, you have to cast from the link pointer back out to the enclosed object (a good use for the offsetof macro if the links can't be at the top of the structure).
A dynamic cast has no language support in C but the circumstance still occurs. If you have a heterogeneous list, then you might verify an object was of a given type using a field in the list's link header. Implemented manually, you would verify the type as being compatible and return NULL if it wasn't. This is special version of the reinterpret cast.
There are many sophisticated programing patterns that require casting so I wouldn't say casting needs to be avoided or indicates something is wrong. The problem with 'C' is how you write the unsafe ones in the same exact way as the safe ones. Keeping it contained and limited is a good practice so you can make sure you have it right (e.g., use library routines, strong typing and asserts if you can).
Casting a result should only done when strictly necessary; if you are using code developed from two different people (such as static libraries, or dynamic libraries), and two functions don't use compatible values, then casting is the only solution (as long as you don't try to cast a string to an integer).
Before to use the casting, it would be better to verify if the datatypes used are correct. In the example code (which has the purpose of providing an example), it doesn't make sense to declare the returned value to be a float value when the function returns a double.