하나의 인수 free(void *)
(Unix V7에 도입 됨)는 mfree(void *, size_t)
여기서 언급하지 않은 이전의 두 인수에 비해 또 다른 주요 이점이 있습니다. 하나의 인수 는 힙 메모리와 함께 작동하는 다른free
모든 API를 극적으로 단순화 합니다. 예를 들어, 메모리 블록의 크기가 필요한 경우 어떻게 든 하나 (포인터) 대신 두 개의 값 (포인터 + 크기)을 반환해야하며 C는 다중 값 반환을 단일 값 반환보다 훨씬 더 번거롭게 만듭니다. 대신 우리는 또는 다른 것을 써야 할 것 입니다 . (요즘에는 두 번째 옵션이 매우 매력적으로 보입니다. NUL로 끝나는 문자열이 "컴퓨팅 역사상 가장 치명적인 디자인 버그" 라는 것을 알고 있기 때문 입니다.free
strdup
char *strdup(char *)
char *strdup(char *, size_t *)
struct CharPWithSize { char *val; size_t size}; CharPWithSize strdup(char *)
, 그러나 그것은 뒤늦은 말입니다. 70 년대에 C의 문자열을 단순하게 처리하는 능력 char *
은 실제로 Pascal 및 Algol과 같은 경쟁사에 비해 확실한 이점으로 간주되었습니다 .) 또한 strdup
이 문제로 인해 고통을받는 것이 아니라 모든 시스템 또는 사용자 정의에 영향을 미칩니다. 힙 메모리를 할당하는 함수.
초기 유닉스 디자이너들은 매우 영리한 사람들이었고 기본적으로 free
더 나은 이유는 여러 가지 가 있습니다 mfree
. 질문에 대한 대답은 그들이 이것을 알아 채고 그에 따라 시스템을 설계했기 때문이라고 생각합니다. 그들이 그 결정을 내리는 순간 그들의 머릿속에서 무슨 일이 일어나고 있었는지에 대한 직접적인 기록을 찾을 수 있을지 의심 스럽습니다. 그러나 우리는 상상할 수 있습니다.
두 인수를 사용하여 V6 Unix에서 실행하기 위해 C로 애플리케이션을 작성한다고 가정합니다 mfree
. 지금까지 잘 관리했지만 프로그램 이 더 야심 차게 되고 힙 할당 변수를 더 많이 사용해야하므로 이러한 포인터 크기를 추적하는 것이 점점 더 번거로워지고 있습니다 . 그러나 당신은 훌륭한 아이디어를 가지고 있습니다. size_t
항상 이러한들을 복사하는 대신 할당 된 메모리 내부에 크기를 직접 숨기는 몇 가지 유틸리티 함수를 작성할 수 있습니다.
void *my_alloc(size_t size) {
void *block = malloc(sizeof(size) + size);
*(size_t *)block = size;
return (void *) ((size_t *)block + 1);
}
void my_free(void *block) {
block = (size_t *)block - 1;
mfree(block, *(size_t *)block);
}
그리고 이러한 새로운 함수를 사용하여 더 많은 코드를 작성할수록 더 멋지게 보입니다. 코드를 더 쉽게 작성할 수있을 뿐만 아니라 코드를 더 빠르게 만듭니다. 두 가지가 자주 함께 사용되지 않습니다! 이들을 size_t
사방에 전달하기 전에는 복사를위한 CPU 오버 헤드를 추가했고 레지스터를 더 자주 (특히 추가 함수 인수의 경우) 유출해야하고 메모리 낭비 (중첩 된 함수 호출이 종종 발생하기 때문에) size_t
다른 스택 프레임에 저장된 여러 사본 ). 새 시스템에서는 여전히 메모리를 사용하여size_t
,하지만 한 번만 해당되며 어디에도 복사되지 않습니다. 이것은 작은 효율성처럼 보일 수 있지만 256KiB의 RAM이있는 하이 엔드 머신에 대해 이야기하고 있음을 명심하십시오.
이것은 당신을 행복하게합니다! 그래서 당신은 다음 유닉스 릴리스에서 작업하는 수염 난 남자들과 멋진 트릭을 공유합니다. 그러나 그것은 그들을 행복하게 만들지 않고 슬프게 만듭니다. 보시다시피, 그들은과 같은 새로운 유틸리티 함수를 추가하는 과정에 strdup
있었고 멋진 트릭을 사용하는 사람들이 새로운 함수를 사용할 수 없다는 것을 알고 있습니다. 새로운 함수는 모두 성가신 포인터 + 크기를 사용하기 때문입니다. API. 그리고 그것은 당신도 슬프게 만듭니다 strdup(char *)
. 시스템 버전을 사용할 수있는 대신 작성하는 모든 프로그램에서 좋은 기능을 직접 다시 작성해야한다는 것을 깨닫기 때문 입니다.
하지만 기다려! 이것은 1977 년이고, 이전 버전과의 호환성은 앞으로 5 년 동안 발명되지 않을 것입니다! 게다가, 아무도 심각한 실제로 사용하지 않고 자사의 오프 색상 이름이 알려지지 않은 "유닉스"일을. K & R의 초판은 현재 출판사로 향하고 있지만 문제가되지 않습니다. 첫 페이지에 "C는 문자열과 같은 복합 객체를 직접 처리하는 작업을 제공하지 않습니다. 힙이 없습니다. ... ". 역사의이 시점에서, string.h
그리고 malloc
벤더 확장은 (!). 따라서 Bearded Man # 1을 제안합니다. 원하는대로 변경할 수 있습니다. 왜 당신의 까다로운 할당자를 공식 할당 자로 선언하지 않습니까?
며칠 후 Bearded Man # 2는 새 API를보고 이전보다 낫다고 말합니다.하지만 여전히 크기를 저장하는 할당 당 전체 단어를 소비하고 있습니다. 그는 이것을 신성 모독의 다음으로 본다. 다른 사람들은 그가 미친 것처럼 그를 쳐다 봅니다. 그날 밤 그는 늦게 머물면서 크기를 전혀 저장하지 않는 새로운 할당자를 발명하지만 대신 포인터 값에 대해 흑 마법 비트 시프트를 수행하여 즉시 유추하고 새 API를 제자리에 유지하면서 교체합니다. 새로운 API는 아무도 스위치를 알아 차리지 못하지만 다음날 아침 컴파일러가 RAM을 10 % 적게 사용한다는 것을 알아 차립니다.
그리고 이제 모두가 행복합니다. 작성하기 쉽고 빠른 코드를 얻고, Bearded Man # 1은 strdup
사람들이 실제로 사용할 수 있는 멋진 간단한 코드를 작성 하고 Bearded Man # 2는 자신이 약간의 이익을 얻었음을 확신합니다. -quines 를 엉망으로 만드는 것으로 돌아갑니다 . 그것을 발송하십시오!
아니면 적어도 그렇게되었을 수도 있습니다.