C에서 어떤 사람들은 포인터를 해제하기 전에 포인터를 던지는 이유는 무엇입니까?


167

나는 오래된 코드베이스에서 일하고 있으며 free ()의 모든 호출은 인수에 캐스트를 사용합니다. 예를 들어

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

여기서 각 포인터는 해당하는 (및 일치하는) 유형입니다. 나는 이것에 전혀 아무런 의미가 없다. 매우 오래된 코드이므로 K & R인지 궁금합니다. 그렇다면 실제로이를 필요로했던 오래된 컴파일러를 지원하고 싶기 때문에 제거하고 싶지 않습니다.

이 캐스트를 사용해야하는 기술적 이유가 있습니까? 나는 그것들을 사용해야 할 실용적인 이유를 많이 보지 못합니다. 데이터 유형을 해제하기 직전에 상기시키는 것이 요점은 무엇입니까?

편집 :이 질문은 다른 질문과 중복 되지 않습니다 . 다른 질문은이 질문의 특별한 경우입니다. 가까운 유권자들이 모든 답을 읽을 것인지는 분명합니다.

Colophon : 이것이 "const answer"에 체크 표시를하는 이유는 이것이 실제적인 이유이기 때문입니다. 그러나 (ANSI C 이전의 관습) (적어도 일부 프로그래머 중 하나)에 대한 대답은 그것이 내 경우에 사용 된 이유 인 것 같습니다. 많은 사람들의 좋은 점이 많습니다. 기부 해 주셔서 감사합니다.


13
"데이터 유형을 해제하기 직전에 데이터 유형을 상기시키는 요점은 무엇입니까?" 사용 가능한 메모리 양을 알고 있습니까?
m0skit0

12
@Codor 컴파일러는 할당 해제를 수행하지 않고 운영 체제는 수행합니다.
m0skit0

20
@ m0skit0 "사용 가능한 메모리가 얼마나되는지 아십니까?" 무료로 얼마를 알기 위해 유형이 필요하지 않습니다. 그런 이유로 캐스팅은 나쁜 코딩입니다.
user694733

9
@ m0skit0 가독성을위한 캐스팅은 캐스팅이 유형을 해석하는 방식을 변경하고 심각한 오류를 숨길 수 있기 때문에 항상 잘못된 코딩입니다. 가독성이 필요할 때 주석이 더 좋습니다.
user694733

66
공룡이 지구를 걸으며 프로그래밍 책을 썼던 고대에는 void*사전 표준 C에는 없었지만 오직 믿었다 char*. 따라서 귀하의 고고 학적 발견으로 매개 변수를 free ()로 캐스팅하는 코드가 밝혀지면 그 시간 또는 그 당시의 생물체가 작성해야한다고 생각합니다. 나는 이것에 대한 어떤 출처도 찾을 수 없으므로 대답하지 않을 것이다.
Lundin

답변:


171

포인터가 인 경우 컴파일러 경고를 해결하기 위해 캐스팅이 필요할 수 있습니다 const. 다음은 free 인수를 캐스트하지 않고 경고를 발생시키는 코드 예제입니다.

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

그리고 컴파일러 (gcc 4.8.3)는 말합니다 :

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;

free((float*) velocity);컴파일러 를 사용 하면 불평이 중지됩니다.


2
@ m0skit0 그것은 누군가가 float*해방되기 전에 왜 캐스팅했는지 설명하지 않습니다 . free((void *)velocity);gcc 4.8.3으로 시도 했습니다. 물론 그것은 것 고대의 컴파일러를 사용하지 작업
마 노스 니콜라이디스

54
왜 상수 메모리를 동적으로 할당해야합니까? 당신은 그것을 사용할 수 없었습니다!
Nils_M

33
@Nils_M 이것은 간단한 예입니다. 함수의 실제 코드에서 수행 한 작업은 비 const 메모리를 할당하고 값을 할당하고 const 포인터에 캐스트하고 반환하는 것입니다. 이제 누군가 할당해야하는 미리 할당 된 const 메모리에 대한 포인터가 있습니다.
Manos Nikolaidis

2
:“이 서브 루틴은 * stringValueP가 가리키는 새로 malloc의 메모리에 문자열을 반환하여 결국 해제해야합니다. 때때로, * stringValueP는 const에 대한 포인터이기 때문에 메모리를 확보하기 위해 사용하는 OS 함수가 인수가 아닌 상수에 대한 포인터를 가져 오도록 선언되는 경우가 있습니다.”
Carsten S

3
잘못된 함수가 const char *p인수로 받아 들여서 해제하면 free를 호출 p하기 char*전에 올바른 캐스트 를 수행하지 않는 것 입니다. 그것은 const char *p그것을 수정 *p 하고 그에 따라 선언되어야하기 때문에 처음부터 복용하는 것으로 선언하지 않아야합니다. (그리고 const에 대한 포인터 대신 const 포인터 가 필요한 경우 실제로 합법적이므로 캐스트 없이도 잘 작동하므로 캐스트 할 필요int *const p 가 없습니다 .)
Ray

59

사전 표준 C는 전혀 없었다 void*하지만 char*당신이 전달 된 모든 매개 변수를 캐스팅했다, 그래서. 고대 C 코드를 발견하면 그러한 캐스트를 찾을 수 있습니다.

참고 자료와 비슷한 질문 .

첫 번째 C 표준이 발표되었을 때, malloc을 무료로 프로토 타입이 가진 변경 char*받는 void*그들은 여전히 오늘이 있는지 확인하십시오.

물론 표준 C에서는 그러한 캐스트가 불필요하고 가독성에 해를 끼칩니다.


23
그러나 왜 free이미 같은 유형으로 논쟁을 던지 겠습니까?
jwodder

4
@chux 사전 표준의 문제점은 바로 다음과 같습니다. 사람들은 캐논에 대한 K & R 책을 방금 지적했습니다. K & R 2 판의 여러 예에서 볼 수 있듯이 K & R 자체는 free표준 C에서 매개 변수 캐스트가 작동 하는 방식에 대해 혼란스러워합니다 (캐스트 할 필요가 없음). 나는 1 판을 읽지 않았기 때문에 80 년대 사전 표준 시간에도 혼란 스러웠는지 알 수 없습니다.
Lundin

7
사전 표준 C에는가 void*없었지만 함수 프로토 타입도 없었으므로 freeK & R에서도 인수를 캐스팅하는 것은 여전히 ​​불필요합니다 (모든 데이터 포인터 유형이 동일한 표현을 사용한다고 가정).
Ian Abbott

6
의견에 이미 언급 된 여러 가지 이유로, 나는이 대답이 의미가 있다고 생각하지 않습니다.
R .. GitHub 중지 지원 아이스

4
이 답변이 실제로 관련이있는 답변에 어떤 영향을 미치는지 알 수 없습니다. 원래 질문은에뿐만 아니라 다른 유형으로의 캐스트와 관련이 있습니다 char *. 구형 컴파일러에서는 어떤 의미가 void있습니까? 그러한 캐스트는 무엇을 달성 할 것입니까?
AnT

34

다음은 캐스트없이 free가 실패하는 예입니다.

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

C에서는 경고가 표시 될 수 있습니다 (VS2012에 경고가 표시됨). C ++에서는 오류가 발생합니다.

드문 경우를 제외하고 캐스팅은 코드를 부풀려 버립니다 ...

편집 : 나는 실패를 시연 void*하지 않기 int*위해 캐스팅했다 . int*로 변환 되는 것과 동일하게 작동합니다.void*암시 적 . int*코드가 추가되었습니다 .


질문에 게시 코드에서, 캐스트가 아니라는 것을 참고 void *하지만,에 float *char *. 그 캐스트는 단지 외적인 것이 아니라 잘못되었습니다.
Andrew Henle

1
문제는 실제로 반대에 관한 것입니다.
m0skit0

1
나는 대답을 이해하지 못한다. 어떤 의미에서 free(p)실패 할 것입니까? 컴파일러 오류가 발생합니까?
Codor

1
이것들은 좋은 지적입니다. const수식어 포인터도 마찬가지입니다 .
Lundin

2
volatileC가 더 이상 표준화되지 않았기 때문에 존재했습니다. 그것은 한 하지 C99에 추가했다.
R .. GitHub 중지 지원 아이스

30

오래된 이유 : 1.를 사용 free((sometype*) ptr)하면 코드가 포인터가 free()호출의 일부로 간주되어야하는 유형에 대해 명시 적 입니다. 명시 적 캐스트는 free()(do-it-yourself)로 대체 될 때 유용합니다 DIY_free().

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

A DIY_free()는 (특히) 디버그 모드에서 해제되는 포인터의 런타임 분석을 수행하는 방법입니다. 이것은 종종DIY_malloc() 문장과 전체 메모리 사용 횟수 등을 추가 위해 . 우리 그룹은 더 현대적인 도구가 나타나기 전에이 기술을 몇 년 동안 사용했습니다. free'd 된 아이템이 타입으로 캐스팅 된 것은 원래 할당 된 것입니다.

  1. 메모리 문제 등을 추적하는 데 많은 시간이 소요되었으므로 free typed 캐스팅과 같은 작은 트릭은 디버깅을 검색하고 좁히는 데 도움이됩니다.

최신 : Manos Nikolaidis @@egur가 해결 한 경고 constvolatile경고 . 나는 3 개의 효과에 유의 것이라고 생각 예선 : , , 및constvolatilerestrict .

[편집] @R .. 코멘트char * restrict *rp2 당 추가

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

3
restrict배치 된 위치 때문에 문제가 rp되지 않습니다. 이는 지정된 유형이 아닌 객체에 영향을줍니다 . 대신에을 가지고 있다면 char *restrict *rp문제가 될 것입니다.
R .. GitHub 중지 지원 아이스

16

또 다른 대안 가설이 있습니다.

우리는 프로그램이 그것의 프로토 타입 불일치의 어떤 종류의 주위에 작동하지 않을 수 있다는 것을 의미 사전 C89, 기록 된 것으로 전해지고 있습니다 free만 아니었다 때문에를,이 같은 것은 없기 때문에 constvoid *, 같은 것은 거기 없었다 이전 C89에 C89 이전 의 함수 프로토 타입 stdlib.h그 자체가위원회의 발명이었다. 시스템 헤더 free가 전혀 선언 하지 않으면 다음과 같이했을 것입니다.

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

여기서 핵심은 함수 프로토 타입이 없다는 것은 컴파일러가 인자 타입 검사를 하지 않았다는 것을 의미합니다 . 기본 인수 프로모션 (Variadic 함수 호출에 여전히 적용되는 것과 동일한 프로모션)을 적용했으며 그 결과였습니다. 각 호출 사이트에서 인수를 작성하는 책임은 수신자의 기대 와 일치하며 전적으로 프로그래머에게 있습니다.

그러나 이것이 여전히 free대부분의 K & R 컴파일러 에서 인수를 제출해야한다는 의미는 아닙니다 . 같은 기능

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

올바르게 컴파일되었습니다. 그래서 우리가 여기에 가지고있는 것은 비정상적인 환경, 예를 들어 sizeof(float *) > sizeof(int)컴파일러 가 그렇지 않은 환경에 대한 버그가있는 컴파일러에 대처하기 위해 작성된 프로그램이라고 생각합니다. 당신이 시점에서 그들을 캐스팅하지 않는 포인터에 대한 적절한 호출 규칙을 사용합니다 전화

나는 그러한 환경을 알고 있지 않지만 그것이 존재하지 않았다는 것을 의미하지는 않습니다. 가장 유망한 후보는 1980 년대 초 8 비트 및 16 비트 마이크로를위한 "작은 C"컴파일러입니다. 또한 초기 크레이 (Crays) 초기에 이와 같은 문제가 있다는 것을 알고 놀랄 일이 아닙니다.


1
상반기 나는 완전히 동의합니다. 그리고 후반은 흥미롭고 그럴듯한 추측입니다.
chux-Reinstate Monica

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.