일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 프로그래밍
- Visual Studio
- 문법
- Desktop
- 알고리즘
- 포인터
- Win32
- Programming
- Tips프로그래밍강좌
- 연산자
- Javascript
- Windows
- 함수
- Direct2D
- tipssoft
- VS ERROR
- 지식나눔강좌
- Tips강좌
- 백준
- 이지스퍼블리싱
- c++
- 티스토리
- CS
- 배열
- c
- c#
- doit코틀린프로그래밍
- 리뷰
- Kotlin
- 김성엽
- Yesterday
- Today
- Total
F.R.I.D.A.Y.
calloc의 인자는 왜 두 개가 필요할까? 본문
위 포스트에 댓글로 들어온 질문입니다. malloc 함수를 사용할 때와 달리 왜 calloc 함수는 두 개의 인자를 받아야 할까요?
calloc()
이전 포스트에서도 말한 것과 같이 calloc 함수는 malloc 함수로 받은 메모리 공간을 0으로 초기화하여 메모리 시작 주소를 반환하는 함수입니다. 인자 두 개가 필요한 것은 메모리 공간을 0으로 초기화할 때 필요합니다.
다음 코드를 보겠습니다.
#include <stdlib.h>
int main(void){
char *ci;
int *pi;
ci = malloc(sizeof(char) * 100);
pi = malloc(sizeof(int) * 25);
for(int i = 0 ; i < 100; ++i){
ci[i] = 0;
}
for(int i = 0 ; i < 25; ++i){
pi[i] = 0;
}
.
.
.
free(ci); free(pi);
return 0;
}
int 타입의 공간 25개, char 타입의 공간 100개를 할당받아 그 공간을 0으로 초기화하는 코드입니다.
여기서 질문입니다. ci와 pi 변수가 가리키는 메모리 블록은 각각 몇 byte일까요? 두 변수 모두 100byte만큼의 메모리 시작 주소를 가지고 있습니다.
그런데, 이 100byte의 공간을 초기화한다고 하였을 때, 어떤 블록이 더 빨리 초기화가 이루어질까요?
for(int i = 0 ; i < 100; ++i){ // char 공간 초기화
ci[i] = 0;
}
for(int i = 0 ; i < 25; ++i){ // int 공간 초기화
pi[i] = 0;
}
반복문의 반복 부분을 보면 char 타입으로 할당받은 공간은 100번, int 타입으로 할당받은 공간은 25번으로 반복 횟수가 4배나 차이 납니다. 여기서 우리는 예상할 수 있습니다.
calloc 함수의 두 번째 인자가 초기화 횟수에 영향을 준다라고 말입니다.
실제로 그러한지 확인해봅니다.
GCC 코드 살펴보기
gcc 컴파일러의 calloc() 코드를 찾아봅니다.
PTR
calloc (size_t nelem, size_t elsize)
{
register PTR ptr;
if (nelem == 0 || elsize == 0)
nelem = elsize = 1;
ptr = malloc (nelem * elsize);
if (ptr) bzero (ptr, nelem * elsize); // check!
return ptr;
}
// https://github.com/gcc-mirror/gcc/blob/master/libiberty/calloc.c
보면 <check!> 라인에서 bzero 함수를 호출하는 것을 알 수 있습니다. 그럼 bzero 함수를 확인해봅니다.
void
bzero (void *to, size_t count)
{
memset (to, 0, count);
}
memset 함수를 사용하는 것을 알 수 있습니다. memset 함수의 경우에는 어떠한 값이 두 번째 인자에 1바이트의 값만 받을 수 있으므로 calloc 함수에서 두 번째 인자로 값을 몇을 넘기던 메모리의 크기만큼 반복을 함을 알 수 있습니다.
// 참고
PTR
memset (PTR dest, register int val, register size_t len)
{
register unsigned char *ptr = (unsigned char*)dest;
while (len-- > 0)
*ptr++ = val;
return dest;
}
이런! 예상했던 것과는 달리 calloc 함수에서 두 번째 인자는 굳이 필요하지 않았습니다. 그럼 calloc 함수를 만들었던 개발자는 왜 이렇게 두 번째 인자를 추가로 작성했을까요? stackoverflow에서도 찾아보고 많은 곳에서 찾아보아도 특정한 이유로 두 개의 인자를 갖게 되었다는 이야기는 하지 않고 있습니다. 단지
- 역사적으로 그래 왔으니까.
- 인자 두 개로 작성하는 것이 더 명확하니까.
등을 추측할 뿐입니다. 실제로도 malloc 함수가 사용한 하나의 인자 방식보다는 calloc 함수가 사용하는 두 개의 인자 방식이 각 요소의 크기와 그 요소의 개수를 파악하는데 더 쉽게 느껴지는 것이 사실입니다.
그럼 현재에는 calloc 함수의 인자를 하나로 변경하면 안 되냐는 질문이 있을 수 있습니다. 그러나, 이러한 구조를 변경하는 것은 IT 생태계에 큰 걸림돌이 될 수 있습니다. 구조를 변경하기 전 calloc 함수를 사용하던 프로그램들은 함수 구조의 변경으로 인해 불필요한 작업을 거쳐야 하니 말입니다. 이전 세대의 프로그램과의 호환성을 위해 이제는 더 이상 사용하지 않을 함수, 구조들도 유지하는 프로그램이 많이 있습니다.
'DEV > C C++' 카테고리의 다른 글
비트 연산자 : 종류 (0) | 2019.12.20 |
---|---|
void 포인터(메모리) (0) | 2019.12.08 |
매크로 함수를 사용할 때 주의할 점 (2) | 2019.11.26 |
함수 포인터를 배워야 하는 이유2 : callback 함수 (4) | 2019.11.17 |
주가 스팬 계산하기 (1) | 2019.11.14 |