무료()가 내 어레이의 길이를 알고 있다면 왜 내 코드로 요청할 수 없는가?
동적으로 할당된 어레이의 길이를 해당 어레이를 조작하는 기능에 전달하는 것이 일반적인 관례라는 것을 알고 있다.
void initializeAndFree(int* anArray, size_t length);
int main(){
size_t arrayLength = 0;
scanf("%d", &arrayLength);
int* myArray = (int*)malloc(sizeof(int)*arrayLength);
initializeAndFree(myArray, arrayLength);
}
void initializeAndFree(int* anArray, size_t length){
int i = 0;
for (i = 0; i < length; i++) {
anArray[i] = 0;
}
free(anArray);
}
하지만 포인터로부터 할당된 메모리 길이를 얻을 방법이 없다면 어떻게 해야 할까?free()
내가 주는 게 같은 포인터인데 뭘 할당한지 알아?왜 나는 C 프로그래머로서 마술을 할 수 없는가?
어디에 있는가?free()
그 자유로운 지식을 얻을 수 있을까?
표준이 제공하지 않는 Klatchko의 정확한 지적 외에도, 실제 malloc/free 구현은 종종 당신이 요구하는 것보다 더 많은 공간을 할당한다. 예를 들어 12바이트를 요구하면 그것은 16을 제공할 수 있다(A Memory Assignator, 16은 일반적인 크기라고 언급하는 A Memory Assignator 참조).그러니까 12바이트를 요구했다는 것을 알 필요는 없고, 단지 16바이트짜리 덩어리를 줬다는 것 뿐이지.
메모리 할당자가 할당된 블록 앞에 배치하는 메타데이터를 얻을 수 있지만, 이는 포인터가 실제로 동적으로 할당된 블록에 대한 포인터일 경우에만 작동한다.이는 단순한 자동 또는 정적 배열을 말하기 보다는 모든 전달된 인수가 그러한 블록에 대한 포인터가 되어야 함을 요구하는 기능의 효용성에 심각한 영향을 미칠 것이다.
포인트는 포인터를 검사하여 포인터가 가리키는 메모리의 종류를 알 수 있는 휴대용 방법이 없다는 것이다.그래서 그것이 흥미로운 아이디어이긴 하지만 특별히 안전한 제안은 아니다.
안전하고 휴대할 수 있는 방법은 그 길이를 유지하기 위해 할당의 첫 단어를 예약하는 것이다.GCC(및 일부 다른 컴파일러)는 길이가 0인 구조를 사용하여 이를 구현하는 비이동식 방법을 지원하며, 휴대용 솔루션에 비해 코드를 다소 단순화한다.
typedef struct
{
size_t length ;
char alloc[0] ; // Compiler specific extension!!!
} tSizedAlloc ;
// Allocating a sized block
tSizedAlloc* blk = malloc( sizeof(tSizedAlloc) + length ) ;
blk->length = length ;
// Accessing the size and data information of the block
size_t blk_length = blk->length ;
char* data = blk->alloc ;
클라치코의 대답을 읽은 후, 나 자신도 해 보고 또 해보았다.ptr[-1]
실제 메모리 저장(일반적으로 분할 오류에 대비하여 저장하기 위해 요청한 메모리보다 많음)
{
char *a = malloc(1);
printf("%u\n", ((size_t *)a)[-1]); //prints 17
free(a);
exit(0);
}
GCC는 크기가 다른 메모리를 다음과 같이 할당한다.
처음에 할당된 메모리는 17바이트 입니다.
할당된 메모리는 요청된 크기보다 5바이트 이상 많으며, 더 많이 요청하면 8바이트를 더 할당한다.
- 크기가 [0,12]이면 할당된 메모리는 17이다.
- 크기가 [13]이면 할당된 메모리는 25이다.
- 크기가 [20]이면 할당된 메모리는 25이다.
- 크기가 [21]이면 할당된 메모리는 33이다.
C위원회가 기준에서 그런 것을 요구하지 않았기 때문에 받을 수 없다.
일부 비휴대용 코드를 쓸 의향이 있는 경우, 다음과 같은 혜택을 누리십시오.
*((size_t *)ptr - 1)
또는 다음 중 하나일 수 있음:
*((size_t *)ptr - 2)
그러나 그 효과가 있는지는 당신이 사용하는 malloc의 구현이 정확히 어디에 그 데이터를 저장하느냐에 달려있다.
이 실이 좀 오래된 건 알지만 그래도 할 말이 있어.malloc_usable_size() 함수가 있다(또는 매크로, 아직 라이브러리를 확인하지 않음). - 힙에서 할당된 메모리 블록 크기를 얻는다.맨 페이지는 디버깅을 위한 것이라고만 명시하고 있는데, 이것은 당신이 요청한 숫자가 아니라 조금 더 큰 할당 번호로 출력되기 때문이다.GNU 확장인 걸 주목하라.
반면에, 메모리 덩어리의 크기를 알 필요가 없다고 믿기 때문에, 필요조차 없을 수도 있다.청크를 담당하는 핸들/설명자/구조만 제거하십시오.
비표준적인 방법은 사용하는 것이다.이 기능을 사용하면 코드가 휴대할 수 없게 된다.또한 문서화에는 다음 번호로 전달된 번호를 반환할 것인지 여부가 명확하지 않다.malloc()
또는 실제 블록 크기(확대해야 함).
할 수 있는 일이다.malloc
이 데이터를 저장하는 방법 구현자.가장 흔히 길이는 할당된 메모리 바로 앞에 저장된다(7바이트를 할당하려면 메타데이터를 저장하는 데 x 추가 바이트가 사용되는 현실에서 7+x바이트가 할당된다).때때로 메타데이터는 할당된 메모리 전후에 저장되어 힙 손상을 검사한다.그러나 구현자는 메타데이터를 저장하기 위해 여분의 데이터 구조를 사용할 수도 있다.
저장 크기에 더 많은 메모리를 할당할 수 있음:
void my_malloc(size_t n,size_t size )
{
void *p = malloc( (n * size) + sizeof(size_t) );
if( p == NULL ) return NULL;
*( (size_t*)p) = n;
return (char*)p + sizeof(size_t);
}
void my_free(void *p)
{
free( (char*)p - sizeof(size_t) );
}
void my_realloc(void *oldp,size_t new_size)
{
// ...
}
int main(void)
{
char *p = my_malloc( 20, 1 );
printf("%lu\n",(long int) ((size_t*)p)[-1] );
return 0;
}
삭제[]에 대한 질문에 답하기 위해 C++의 초기 버전에서는 실제로 delete[n]로 전화를 걸어 런타임에 크기를 알려야 하므로, 삭제할 필요가 없었다.슬프게도, 이 행동은 "너무 혼란스러운" 것으로 제거되었다.
(자세한 내용은 D&E를 참조하십시오.)
'Programing' 카테고리의 다른 글
C의 int 변수에 이중 정밀도를 할당하는 비직관적 결과 (0) | 2022.04.17 |
---|---|
Vue.js - 요소 UI - 폼 유효성 검사 상태를 확인하는 방법 (0) | 2022.04.17 |
Java 클라이언트에서 서버의 자체 서명 SSL 인증서 수락 (0) | 2022.04.17 |
유닉스 도메인 소켓 VS 명명된 파이프? (0) | 2022.04.17 |
JVM에서 기본 로캘을 설정하는 방법 (0) | 2022.04.17 |