수행의 차이점은 무엇입니까?
ptr = (char **) malloc (MAXELEMS * sizeof(char *));
또는:
ptr = (char **) calloc (MAXELEMS, sizeof(char*));
malloc 대신 calloc을 사용하거나 그 반대로 사용하는 것이 좋은 생각은 언제입니까?
ptr = calloc(MAXELEMS, sizeof(*ptr));
수행의 차이점은 무엇입니까?
ptr = (char **) malloc (MAXELEMS * sizeof(char *));
또는:
ptr = (char **) calloc (MAXELEMS, sizeof(char*));
malloc 대신 calloc을 사용하거나 그 반대로 사용하는 것이 좋은 생각은 언제입니까?
ptr = calloc(MAXELEMS, sizeof(*ptr));
답변:
calloc()
초기화 malloc()
되지 않은 버퍼를 제공하는 동시에 메모리는 초기화되지 않습니다.
대규모 할당의 경우 calloc
주류 OS에서 구현되는 대부분의 구현은 OS에서 0으로 알려진 페이지 (예 : POSIX mmap(MAP_ANONYMOUS)
또는 Windows 를 통해)를 가져 오므 VirtualAlloc
로 사용자 공간에이를 작성할 필요가 없습니다. 이것은 정상적인 방법으로 malloc
OS에서 더 많은 페이지를 얻는 방법입니다 . calloc
OS 보증을 활용합니다.
이것은 calloc
메모리가 여전히 "깨끗하고"느리게 할당 될 수 있으며, 기록 중 복사가 시스템 전체의 공유 물리적 페이지 0에 매핑 될 수 있음을 의미 합니다. (가상 메모리가있는 시스템을 가정합니다.)
일부 컴파일러는 malloc + memset (0)을 calloc으로 최적화 할 수도 있지만 메모리를로 읽으려면 calloc을 명시 적으로 사용해야합니다 0
.
쓰기 전에 메모리를 읽지 않으 malloc
려면 OS에서 새 페이지를 가져 오는 대신 내부 여유 목록에서 더티 메모리를 제공 할 수 있습니다. (또는 작은 할당을 위해 사용 가능한 목록에서 메모리 블록을 0으로 만드는 대신).
OS가없는 경우 임베디드 구현은 메모리를 제로 메모리 calloc
로 남겨 두거나 calloc
프로세스 간 정보 유출을 막기 위해 페이지를 0으로 만드는 멋진 다중 사용자 OS가 아닙니다.
임베디드 Linux에서 malloc은 mmap(MAP_UNINITIALIZED|MAP_ANONYMOUS)
다중 사용자 시스템에서 안전하지 않기 때문에 일부 임베디드 커널에서만 사용할 수 있습니다.
calloc
OS가 속도를 높이기 위해 몇 가지 트릭을 수행 할 수 있기 때문에 반드시 더 비싸지는 않습니다. FreeBSD는 유휴 CPU 시간이되면 그것을 사용하여 할당 취소 된 메모리 블록을 없애고 블록으로 플래그를 표시하는 간단한 프로세스를 실행하는 데 사용합니다. 그래서 당신이 할 때 calloc
, 그것은 먼저 사전에 0으로 된 블록 중 하나를 찾아서 당신에게 줄 것입니다-대부분 그것을 찾을 것입니다.
덜 알려진 차이점은 Linux와 같이 낙관적 메모리 할당을 사용하는 운영 체제 malloc
에서 프로그램이 실제로 해당 메모리에 닿을 때까지 반환되는 포인터 가 실제 메모리에 의해 지원되지 않는다는 것입니다.
calloc
실제로 메모리를 만지므로 (0을 씁니다) 따라서 OS가 실제 RAM (또는 스왑)으로 할당을 백업하고 있는지 확인할 수 있습니다. 이것이 malloc보다 속도가 느린 이유이기도합니다 (0으로 설정해야 할뿐만 아니라 OS는 다른 프로세스를 교체하여 적절한 메모리 영역을 찾아야합니다).
malloc의 동작에 대한 추가 논의는 예를 들어이 SO 질문 을 참조하십시오
calloc
0을 쓸 필요가 없습니다. 할당 된 블록이 운영 체제에서 제공하는 대부분의 새 0 페이지로 구성되어 있으면 해당 블록은 그대로 유지됩니다. 물론 이것은 calloc
일반 라이브러리 함수 대신 운영 체제에 맞게 조정해야합니다 malloc
. 또는 구현 calloc
자는 각 단어를 0 화하기 전에 0과 비교할 수 있습니다. 시간이 절약되지는 않지만 새 페이지가 더러워지지는 않습니다.
dlmalloc
유사 구현 memset
은 mmap
새 익명 페이지 (또는 이와 동등한) 를 통해 청크를 얻은 경우 생략합니다 . 일반적으로 이러한 종류의 할당은 256k 정도에서 시작하여 더 큰 청크에 사용됩니다. 나는 제 자신을 제외하고 0을 쓰기 전에 0과 비교하는 구현을 모른다.
omalloc
또한 memset
; calloc
응용 프로그램에서 아직 사용하지 않은 페이지 (페이지 캐시)를 건드리지 않아도됩니다. 그러나 매우 원시적 인 calloc
구현 은 다릅니다.
종종 간과되는 장점 중 하나 calloc
는 (적합한 구현) 정수 오버플로 취약점으로부터 사용자를 보호하는 데 도움이된다는 것입니다. 비교:
size_t count = get_int32(file);
struct foo *bar = malloc(count * sizeof *bar);
vs.
size_t count = get_int32(file);
struct foo *bar = calloc(count, sizeof *bar);
전자 count
가보다 크면 작은 할당 및 후속 버퍼 오버플로가 발생할 수 있습니다 SIZE_MAX/sizeof *bar
. 이 경우 후자는 큰 개체를 만들 수 없으므로 자동으로 실패합니다.
물론 오버플로 가능성을 무시하는 부적합한 구현에주의를 기울여야 할 수도 있습니다. 이것이 목표로하는 플랫폼에서 문제가된다면 어쨌든 오버플로에 대한 수동 테스트를 수행해야합니다.
char
이다 하지 (A) 내로 결과 다시 할당하는 경우에 오버 플로우가 아니라 구현 정의 변환 char
개체.
size_t
64 비트이므로 문제 없습니다"인 경우 보안 버그로 이어질 잘못된 사고 방식입니다. size_t
는 크기를 나타내는 추상 유형이며 32 비트 숫자의 임의의 곱을 생각할 이유가 없으며 size_t
(참고 : sizeof *bar
64 비트 C 구현에서는 원칙적으로 2 ^ 32보다 클 수 있습니다!)에 적합 size_t
합니다.
이 문서는 calloc을 malloc처럼 보이게 만듭니다. 메모리는 0으로 초기화됩니다. 이것은 주요 차이점이 아닙니다! calloc의 아이디어는 메모리 할당을위한 copy-on-write 의미를 생략하는 것입니다. calloc을 사용하여 메모리를 할당하면 모든 물리적 페이지가 0으로 초기화되는 동일한 물리적 페이지에 매핑됩니다. 할당 된 메모리의 임의의 페이지가 물리적 페이지에 기록 될 때 할당됩니다. 예를 들어 비어있는 해시 부분이 추가 메모리 (페이지)에 의해 백업되지 않기 때문에 HUGE 해시 테이블을 만드는 데 종종 사용됩니다. 그것들은 행복하게 초기화 된 단일 페이지를 가리키며 프로세스 간에도 공유 할 수 있습니다.
모든 가상 주소에 쓰기는 페이지에 맵핑되며, 해당 페이지가 0 페이지 인 경우 다른 물리적 페이지가 할당되고 0 페이지가 복사되고 제어 플로우가 클라이언트 프로세스로 리턴됩니다. 메모리 매핑 파일, 가상 메모리 등이 작동하는 방식과 동일하게 작동합니다. 페이징을 사용합니다.
여기 주제에 대한 최적화 이야기가 있습니다 : http://blogs.fau.de/hager/2007/05/08/benchmarking-fun-with-calloc-and-zero-pages/
할당 된 메모리 블록의 크기에는 차이가 없습니다. calloc
메모리 블록을 물리적 인 0 비트 패턴으로 채 웁니다. 실제로 할당 된 메모리 블록에있는 객체 calloc
는 마치 리터럴로 초기화 된 것처럼 초기 값 을 갖는다 고 가정합니다 0
. 즉, 정수는 0
부동 소수점 변수 -value- 0.0
포인터-적절한 null 포인터 값 , 등등.
그러나 pedantic 관점에서 calloc
(뿐만 아니라 memset(..., 0, ...)
) 유형의 객체를 (0으로) 올바르게 초기화하는 것만 보장됩니다 unsigned char
. 다른 모든 것은 제대로 초기화되지 않으며 , 소위 트랩 표현을 포함하여 정의되지 않은 동작을 유발할 수 있습니다. 다시 말해서, unsigned char
상기 언급 된 모든 0 비트 이외 의 유형에 대해 patterm은 잘못된 값, 트랩 표현을 나타낼 수 있습니다.
나중에 Technical Corrigenda to C99 표준 중 하나에서 동작은 모든 정수 유형에 대해 정의되었습니다. 즉, 공식적으로 현재 C 언어에서는 calloc
(및 memset(..., 0, ...)
)로 정수 유형 만 초기화 할 수 있습니다 . 일반적인 경우에이를 사용하여 C 언어의 관점에서 정의되지 않은 동작이 발생합니다.
실제로, calloc
우리 모두가 알고 있듯이 작동하지만, 위의 사항을 고려할 것인지의 여부는 귀하에게 달려 있습니다. 나는 개인적으로 그것을 완전히 피하고 malloc
대신 사용하고 내 자신의 초기화를 수행 하는 것을 선호합니다 .
마지막으로, 또 다른 중요한 세부 사항은 요소 크기에 요소 수를 곱하여 calloc
최종 블록 크기를 내부적 으로 계산하는 데 필요 하다는 것 입니다 . 그렇게하는 동안 calloc
산술 오버플로가 발생할 수 있는지 확인 해야합니다. 요청 된 블록 크기를 올바르게 계산할 수 없으면 할당 실패 (널 포인터)가 발생합니다. 한편,malloc
버전은 오버플로를 감시하지 않습니다. 오버플로가 발생하는 경우 "예측할 수없는"메모리 양을 할당합니다.
memset(p, v, n * sizeof type);
가 발생할 수 있기 때문에 문제가 되는 것 같습니다 n * sizeof type
. for(i=0;i<n;i++) p[i]=v;
강력한 코드를 위해 루프 를 사용해야 할 것 같아요 .
n
요소의 크기가있는 요소가 있는 배열 이 있으면 객체의 최대 크기가보다 작아야하므로 오버플 sizeof type
로 n*sizeof type
할 수 없습니다 SIZE_MAX
.
SIZE_MAX
이지만 여기 에는 배열 이 없습니다 . 에서 반환 된 포인터 calloc()
가 초과 한 것보다 할당 된 메모리를 가리킬 수 있습니다 SIZE_MAX
. 대부분의 구현에 2 개 인수의 제품을 제한 할 calloc()
에 SIZE_MAX
, 아직 C 사양은 제한을 부과하지 않습니다.
기사의 은 calloc 재미를 벤치마킹 () 및 제로 페이지 에 게오르그 헤거의 블로그
calloc ()을 사용하여 메모리를 할당 할 때 요청 된 메모리 양이 즉시 할당되지 않습니다. 대신, 메모리 블록에 속하는 모든 페이지는 일부 MMU 매직 (아래 링크)에 의해 모든 0을 포함하는 단일 페이지에 연결됩니다. 이러한 페이지가 읽기 전용 인 경우 (원래 벤치 마크 버전의 배열 b, c 및 d에 해당) 데이터는 단일 제로 페이지에서 제공되며 물론 캐시에 적합합니다. 메모리 바운드 루프 커널의 경우 너무 많습니다. 어떤 방법 으로든 페이지에 쓰면 오류가 발생하고 "실제"페이지가 매핑되고 0 페이지가 메모리에 복사됩니다. 이것을 잘 알려진 최적화 접근 방식 (copy-on-write)이라고합니다 (C ++ 강의에서 여러 번 가르쳤습니다). 그 후
calloc
일반적 malloc+memset
으로 0입니다
일반적으로 malloc+memset
다음과 같은 작업을 수행 할 때 명시 적 으로 사용하는 것이 약간 좋습니다 .
ptr=malloc(sizeof(Item));
memset(ptr, 0, sizeof(Item));
sizeof(Item)
컴파일 타임에 컴파일러에 대해 알고 있기 때문에 컴파일러 가 더 좋으며 대부분의 경우 컴파일러는 메모리를 제로화하는 가장 좋은 명령으로 대체합니다. 반면에에서 memset
발생 calloc
하는 경우 할당의 매개 변수 크기가 calloc
코드 에서 컴파일되지 않고 실제 memset
호출되는 경우가 많습니다. 여기에는 일반적으로 채우기주기보다 긴 경계까지 바이트 단위 채우기를 수행하는 코드가 포함됩니다. sizeof(long)
청크 단위로 메모리를 채우고 마지막으로 남은 공간을 바이트 단위로 채 웁니다. 할당자가 일부를 호출하기에 충분히 똑똑하더라도aligned_memset
여전히 일반 루프입니다.
주목할만한 예외는 매우 큰 메모리 청크 (일부 power_of_two 킬로바이트)의 malloc / calloc을 수행하는 경우 커널에서 직접 할당을 수행 할 수 있습니다. OS 커널은 일반적으로 보안상의 이유로 모든 메모리를 제로화하므로, 충분한 calloc은 추가 제로화로이를 반환 할 수 있습니다. 다시 말하지만, 당신이 아는 것을 할당하는 것이 작 으면 malloc + memset 성능 측면에서 더 나을 수 있습니다.
calloc()
느립니다 malloc()
: 크기의 곱셈. malloc ()은 종종 컴파일 시간 상수를 갖는 반면 calloc()
일반 곱셈 ( size_t
64 비트 인 경우에도 매우 비싼 64 비트 * 64 비트 = 64 비트 연산) 을 사용해야합니다 .
struct foo { char a,b,c; };
. calloc
항상 전체 에드 영역 을 지우려면 항상 malloc
+ 보다 낫습니다 . 크기 요소의 int overflow에 대해서도 신중하지만 효율적으로 검사합니다. memset
malloc
calloc
차이 1 :
malloc()
일반적으로 메모리 블록을 할당하고 초기화 된 메모리 세그먼트입니다.
calloc()
메모리 블록을 할당하고 모든 메모리 블록을 0으로 초기화합니다.
차이 2 :
malloc()
구문 을 고려하면 하나의 인수 만 사용합니다. 아래의 다음 예를 고려하십시오.
data_type ptr = (cast_type *)malloc( sizeof(data_type)*no_of_blocks );
예 : int 유형에 10 개의 메모리 블록을 할당하려면
int *ptr = (int *) malloc(sizeof(int) * 10 );
calloc()
구문 을 고려하면 2 개의 인수가 필요합니다. 아래의 다음 예를 고려하십시오.
data_type ptr = (cast_type *)calloc(no_of_blocks, (sizeof(data_type)));
예 : int 유형에 10 블록의 메모리를 할당하고 모든 것을 ZERO에 초기화하려면
int *ptr = (int *) calloc(10, (sizeof(int)));
유사성:
모두 malloc()
와 calloc()
그들이 주조 입력하지 않으면 기본적으로 무효 *를 반환합니다.!
두 가지 차이점이 있습니다.
첫째, 논쟁의 수입니다. malloc()
단일 인수 (바이트 단위의 메모리 필요)를 사용하지만 calloc()
두 개의 인수가 필요합니다.
둘째, 할당 된 메모리를 초기화 malloc()
하지 않고 calloc()
할당 된 메모리를 ZERO로 초기화합니다.
calloc()
메모리 영역을 할당하면 길이는 매개 변수의 곱이됩니다. calloc
메모리를 ZERO로 채우고 첫 번째 바이트에 대한 포인터를 반환합니다. 충분한 공간을 찾지 못하면 NULL
포인터를 반환합니다 .구문 : ptr_var=(cast_type *)calloc(no_of_blocks , size_of_each_block);
즉ptr_var=(type *)calloc(n,s);
malloc()
REQUSTED SIZE의 단일 메모리 블록을 할당하고 첫 번째 바이트에 대한 포인터를 반환합니다. 요청 된 메모리 양을 찾지 못하면 널 포인터를 리턴합니다.구문 : 그동안 함수는, 바이트 수를 할당하는 하나 개의 인자를 취할 기능 소자의 개수 인, 한 개의 인수를, 다른 바이트의 수는 이러한 요소들의 각각에 할당하도록되어있는 것을 특징으로한다. 또한 할당 된 공간을 0으로 초기화하지만 그렇지는 않습니다.ptr_var=(cast_type *)malloc(Size_in_bytes);
malloc()
calloc()
calloc()
malloc()
malloc()
과 calloc()
둘 다 런타임 메모리 할당을 허용 즉, 동적 메모리 할당을 허용 C 표준 라이브러리 함수이다.
프로토 타입은 다음과 같습니다.
void *malloc( size_t n);
void *calloc( size_t n, size_t t)
이 둘 사이에는 주로 두 가지 차이점이 있습니다.
동작 : malloc()
메모리 블록을 초기화하지 않고 할당하고이 블록에서 내용을 읽으면 가비지 값이 발생합니다. calloc()
반면에, 메모리 블록을 할당하고이를 0으로 초기화하며,이 블록의 내용을 읽으면 분명히 0이됩니다.
구문 : malloc()
1 calloc()
개의 인수 ( 할당 된 크기)를 취하고 두 개의 인수 (할당 된 블록 수와 각 블록의 크기)를 사용합니다.
성공했을 경우, 양쪽으로부터의 반환 값은 할당 된 메모리 블록에 대한 포인터입니다. 그렇지 않으면 메모리 할당 실패를 나타내는 NULL 이 반환됩니다.
예:
int *arr;
// allocate memory for 10 integers with garbage values
arr = (int *)malloc(10 * sizeof(int));
// allocate memory for 10 integers and sets all of them to 0
arr = (int *)calloc(10, sizeof(int));
동일한 기능은 다음과 같이 calloc()
하여 얻을 수 malloc()
와 memset()
:
// allocate memory for 10 integers with garbage values
arr= (int *)malloc(10 * sizeof(int));
// set all of them to 0
memset(arr, 0, 10 * sizeof(int));
더 빠르기 때문에 malloc()
사용 하는 것이 바람직 calloc()
합니다. 값을 0으로 초기화하려는 경우 calloc()
대신 사용하십시오.
아직 언급되지 않은 차이점 : 크기 제한
void *malloc(size_t size)
까지만 할당 할 수 SIZE_MAX
있습니다.
void *calloc(size_t nmemb, size_t size);
에 대해 할당 할 수 있습니다 SIZE_MAX*SIZE_MAX
.
이 기능은 선형 주소 지정 기능이있는 많은 플랫폼에서 자주 사용되지 않습니다. 이러한 시스템 calloc()
은nmemb * size <= SIZE_MAX
.
512 바이트 유형을 호출 disk_sector
하고 코드에서 많은 섹터 를 사용하려고합니다 . 여기서 코드는 SIZE_MAX/sizeof disk_sector
섹터 까지만 사용할 수 있습니다 .
size_t count = SIZE_MAX/sizeof disk_sector;
disk_sector *p = malloc(count * sizeof *p);
더 큰 할당을 허용하는 다음을 고려하십시오.
size_t count = something_in_the_range(SIZE_MAX/sizeof disk_sector + 1, SIZE_MAX)
disk_sector *p = calloc(count, sizeof *p);
이제 그러한 시스템이 그러한 큰 할당을 제공 할 수 있다면 또 다른 문제입니다. 오늘날 대부분은 그렇지 않습니다. 때 그러나 그것은 몇 년 동안 발생한 SIZE_MAX
감안할 때 65535이었다 무어의 법칙을 이 특정와 메모리 모델 2030에 대해 발생 될 것입니다 의심 SIZE_MAX == 4294967295
기가 바이트의 100와 메모리 풀.
size_t
32 비트보다 크게 만듭니다 . 유일한 질문은 더 작은 할당에 대한 포인터를 반환하지 않고 calloc
제품이 초과하는 값을 사용하여 SIZE_MAX
0을 산출 할 수 있는지 여부 입니다.
calloc()
할당량을 초과 할 수 있습니다 SIZE_MAX
. 16 비트로 과거에 발생했으며 size_t
메모리가 계속 저렴 해짐에 따라 일반적 이지 않더라도 앞으로 나아갈 수는 없습니다 .
SIZE_MAX
. 그러한 할당이 성공할 수있는 상황이 반드시 필요한 것은 아니다. 그러한 할당을 처리 할 수없는 구현이 반환해야한다는 위임이 특별한 이점이 있는지 확실하지 않습니다 NULL
(특히 일부 구현에서 malloc
아직 커밋되지 않았고 코드가 실제로 사용하려고 할 때 사용할 수없는 공간에 대한 포인터를 반환 하는 것이 일반적 임) 그것).
size_t
에 uint64_t
?
블록 수 :
malloc ()은 요청 된 메모리의 단일 블록을 할당하고
calloc ()은 요청 된 메모리의 여러 블록을 할당합니다
초기화 :
malloc ()-할당 된 메모리를 지우고 초기화하지 않습니다.
calloc ()-할당 된 메모리를 0으로 초기화합니다.
속도 :
malloc ()이 빠릅니다.
calloc ()이 malloc ()보다 느립니다.
인수 및 구문 :
malloc ()은 1 개의 인수를 사용합니다.
바이트
calloc ()은 2 개의 인수를받습니다 :
길이
void *malloc(size_t bytes);
void *calloc(size_t length, size_t bytes);
메모리 할당 방식 :
malloc 함수는 사용 가능한 힙에서 원하는 '크기'의 메모리를 할당합니다.
calloc 함수는 'num * size'와 같은 크기의 메모리를 할당합니다.
이름에 대한 의미 :
malloc이라는 이름은 "메모리 할당"을 의미합니다.
calloc이라는 이름은 "연속 할당"을 의미합니다.
malloc
가족 의 결과를 캐스트하지 않습니다