In C, why do some people cast the pointer before freeing it?

CPointersCasting

C Problem Overview


I'm working on an old code base and pretty much every invocation of free() uses a cast on its argument. For example,

free((float *)velocity);
free((float *)acceleration);
free((char *)label);

where each pointer is of the corresponding (and matching) type. I see no point in doing this at all. It's very old code, so I'm left wondering if it's a K&R thing. If so, I actually wish to support the old compilers that may have required this, so I don't want to remove them.

Is there a technical reason to use these casts? I don't even see much of a pragmatic reason to use them. What's the point of reminding ourselves of the data type right before freeing it?

EDIT: This question is not a duplicate of the other question. The other question is a special case of this question, which I think is obvious if the close voters would have read all the answers.

Colophon: I'm giving the checkmark to the answer that gave a reason why this might still need to be done; however, the answer about it being a pre-ANSI C custom (at least among some programmers) seems to be the reason it was used in my case. If there were two checkmarks to give they'd both get one. Lots of good points by many people here. Thank you for your contributions.

C Solutions


Solution 1 - C

Casting may be required to resolve compiler warnings if the pointers are const. Here is an example of code that causes a warning without casting the argument of free:

const float* velocity = malloc(2*sizeof(float));
free(velocity);

And the compiler (gcc 4.8.3) says:

main.c: In function ‘main’:
main.c:9:5: warning: passing argument 1 of ‘free’ discards ‘const’ qualifier from pointer target type [enabled by default]
     free(velocity);
     ^
In file included from main.c:2:0:
/usr/include/stdlib.h:482:13: note: expected ‘void *’ but argument is of type ‘const float *’
 extern void free (void *__ptr) __THROW;

If you use free((float*) velocity); the compiler stops complaining.

Solution 2 - C

Pre-standard C had no void* but only char*, so you had to cast all parameters passed. If you come across ancient C code, you might therefore find such casts.

Similar question with references.

When the first C standard was released, the prototypes for malloc and free changed from having char* to the void* that they still have today.

And of course in standard C, such casts are superfluous and just harm readability.

Solution 3 - C

Here's an example where free would fail without a cast:

volatile int* p = (volatile int*)malloc(5 * sizeof(int));
free(p);        // fail: warning C4090: 'function' : different 'volatile' qualifiers
free((int*)p);  // success :)
free((void*)p); // success :)

In C you can get a warning (got one in VS2012). In C++ you'll get an error.

Rare cases aside, the casting just bloats the code...

Edit: I casted to void* not int* to demo the failure. It will work the same as int* will be converted to void* implicitly. Added int* code.

Solution 4 - C

Old reason: 1. By using free((sometype*) ptr), code is explicit about the type the pointer should be considered as part of the free() call. The explicit cast is useful when free() is replaced with a (do-it-yourself) DIY_free().

#define free(ptr) DIY_free(ptr, sizeof (*ptr))

A DIY_free() was (is) a way, especially in debug mode, to do run-time analysis of the pointer being freed. This is often paired with a DIY_malloc() to add sententials, global memory usage counts, etc. My group used this technique for years before more modern tools appear. It obliged that the item being free'd was cast to the type is was originally allocated.

  1. Given the many hours spent tracking down memory issues, etc., little tricks like casting the type free'd would aid in searching and narrowing the debugging.

Modern: Avoiding const and volatile warnings as addressed by Manos Nikolaidis@ and @egur. Thought I would note the effects of the 3 qualifiers: const, volatile, and restrict.

[edit] Added char * restrict *rp2 per @R.. comment

void free_test(const char *cp, volatile char *vp, char * restrict rp, 
    char * restrict *rp2) {
  free(cp);  // warning
  free(vp);  // warning
  free(rp);  // OK
  free(rp2);  // warning
}

int main(void) {
  free_test(0,0,0,0);
  return 0;
}

Solution 5 - C

Here is another alternative hypothesis.

We are told that the program was written pre-C89, which means it can't be working around some kind of mismatch with the prototype of free, because not only was there no such thing as const nor void * prior to C89, there was no such thing as a function prototype prior to C89. stdlib.h itself was an invention of the committee. If the system headers bothered to declare free at all, they would have done it like this:

extern free();  /* no `void` return type either! */

Now, the key point here is that the absence of function prototypes meant the compiler did no argument type checking. It applied the default argument promotions (the same ones that still apply to variadic function calls) and that was it. Responsibility for making the arguments at each callsite line up with the callee's expectations lay entirely with the programmer.

However, this still doesn't mean it was necessary to cast the argument to free on most K&R compilers. A function like

free_stuff(a, b, c)
    float *a;
    char *b;
    int *c;
{
    free(a);
    free(b);
    free(c);
}

should have been compiled correctly. So I think what we've got here is a program written to cope with a buggy compiler for an unusual environment: for instance, an environment where sizeof(float *) > sizeof(int) and the compiler wouldn't use the appropriate calling convention for pointers unless you cast them at the point of the call.

I am not aware of any such environment, but that doesn't mean there wasn't one. The most probable candidates that come to mind are cut-down "tiny C" compilers for 8- and 16-bit micros in the early 1980s. I also wouldn't be surprised to learn that early Crays had problems like this.

Solution 6 - C

free takes in only non-const pointers as parameter. So in case of const pointers, explicit casting to a non-const pointer is required.

https://stackoverflow.com/questions/2819535/unable-to-free-const-pointers-in-c

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSO StinksView Question on Stackoverflow
Solution 1 - CManos NikolaidisView Answer on Stackoverflow
Solution 2 - CLundinView Answer on Stackoverflow
Solution 3 - CegurView Answer on Stackoverflow
Solution 4 - Cchux - Reinstate MonicaView Answer on Stackoverflow
Solution 5 - CzwolView Answer on Stackoverflow
Solution 6 - CNobodyView Answer on Stackoverflow