본문 바로가기

StackOverflow

[C] C언어에서, 메모리 포인터를 해제하기 전에 캐스팅해야 하는 이유?

http://stackoverflow.com/questions/34019977/in-c-why-do-some-people-cast-the-pointer-before-freeing-it


Q: C언어에서, 어떤 사람들은 메모리 포인터를 해제하기 전에 캐스팅을 합니다. 왜 그런가요?

메모리를 해제할 때 free를 이용하게 되는데, 각 포인터는 자신의 타입을 가지고 있습니다. 그런데 왜 캐스팅을 해줘야 하죠? 이런 일을 하는 뭔가 기술적인 이유가 있나요?

 (질문자: Dr. Person Person II)


A : const로 할당된 dynamic 메모리를 해제할 때, 컴파일러가 에러를 발생시키는 경우가 있습니다. 이 경우 캐스팅을 해주면 컴파일 에러를 막을 수 있습니다. (답변자:Manos Nikolaidis)

-> 근데 왜 const 변수를 dynamic으로 할당하죠? 처음 설정된 값이 영원히 변하지 않을테니, 그렇게하지 않아도 될텐데요 (Nils_M)

-> 이건 그냥 한가지 예일 뿐입니다. (Manos Nikolaidis)


A : 비표준 C에서는 void*가 없었기 때문에, char*를 이용해서 메모리를 일단 할당한 뒤 다른 타입으로 강제로 캐스팅해서 썼습니다. C의 첫번째 표준안에서 메모리 할당이나 해제의 기본이 char*가 아닌, void* 로 정해졌고, 오늘날까지 이어지고 있습니다. 최신 컴파일러를 이용한다면, 이런 코드는 가독성을 떨어뜨릴 뿐입니다. (답변자 Lundin)



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 read all the answers.

shareeditflag
13
 
"What's the point of reminding ourselves of the data type right before freeing it?" Maybe to know how much memory will be freed? – m0skit0 2 days ago
11
 
@Codor The compiler doesn't do the deallocation, the operating system does. – m0skit0 2 days ago
14
 
@m0skit0 "Maybe to know how much memory will be freed?" Type is not necessary to know how much to free. Cast for that reason only is bad coding. – user694733 2 days ago
9
 
@m0skit0 Casting for readabilitys sake is always bad coding, because casting changes how types are interpreted and it may hide serious errors. When readability is needed, comments are better. – user694733 2 days ago
58
 
In ancient days when dinosaurs walked the earth, and wrote programming books, I believe there was novoid* in pre-standard C, but only char*. So if your archaeological findings reveal code casting the parameter to free(), I believe it must either be from that time period, or written by a creature from that time. I can't find any source for this though, so I'll refrain from answering. – Lundin 2 days ago 

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.

shareeditflag
  
 
An excellent point. – Dr. Person Person II 2 days ago
2
 
@m0skit0 that doesn't explain why someone would cast to float* before freeing. I tried free((void *)velocity); with gcc 4.8.3. Of course it wouldn't work with an ancient compiler – Manos Nikolaidis 2 days ago 
39
 
But why would you need to dynamically allocate constant memory? You could never use it! – Nils_M 2 days ago
22
 
@Nils_M it's a simplified example to make a point. What I have done in actual code in a function is allocate non-const memory, assign values, cast to a const pointer and return it. Now, there is a pointer to preassigned const memory that someone has to free. – Manos Nikolaidis 2 days ago
2
 
Example:“These subroutines return the string in newly malloc'ed memory, pointed to by *stringValueP, that you must eventually free. Sometimes, the OS function you use to free memory is declared to take a pointer to something non-constant as its argument, so because *stringValueP is a pointer to a const.” – Carsten S 2 days ago

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.

shareeditflag
13
 
But why would you cast the argument to free to the same type that it already is? – jwodder 2 days ago
3
 
@chux The problem with pre-standard is just that: there are no obligations for anything. People just pointed at the K&R book for canon because that was the only thing they had. And as we can see from several examples in K&R 2nd edition, K&R themselves are confused about how casts of the parameter tofree work in standard C (you don't need to cast). I haven't read the 1st edition so I can't tell if they were confused in the 80s pre-standard times as well. – Lundin 2 days ago 
3
 
Pre-standard C didn't have void*, but it didn't have function prototypes either, so casting the argument of free was still unnecessary even in K&R (assuming all data pointer types used the same representation). – Ian Abbott 2 days ago 
4
 
For multiple reasons stated in the comments already, I don't think this answer makes sense. – R.. 2 days ago
3
 
I don't see how this answer would really answer anything relevant. The original question involves casts to other types, not only to char *. What sense would it make in old compilers without void? What would such casts achieve? – AnT 2 days ago

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.

shareeditflag
  
 
Note that in the code posted in the question, the casts are not to void *, but to float * and char *. Those casts are not just extraneous, they're wrong. – Andrew Henle 2 days ago
1
 
The question is actually about the opposite. – m0skit0 2 days ago 
1
 
I don't understand the answer; in what sense would free(p) fail? Would it give a compiler error? – Codor2 days ago 
1
 
These are good points. Same goes with const qualifier pointers, obviously. – Lundin 2 days ago
2
 
volatile has existed since C was standardized if not longer. It was not added in C99. – R.. 2 days ago