메모리 관련 함수 : memset, bzero, memcpy, memccpy, memmove, memchr, memcmp
dqQQQ
·2023. 11. 25. 10:50
메모리 구조
.code 영역
소수의 예외도 있지만 모든 프로그램은 main문이 있어야 실행이 가능하다.
.code영역은 실행할 프로그램의 main문 안의 코드들을 저장한다.
.data 영역
main문을 제외하고의 코드를 의미한다. 전역변수를 말하는 것이며
static을 사용하여 정적 변수로 선언해도 같다.
.stack 영역
흔히 말하는 스택 프레임에 해당 하는 영역이다.
프로그램이 함수 호출 같은 때에 자동으로 사용하는 임시 저장공간이라고 생각하면 편하다.
함수가 호출되면 ret주소를 저장하고 base pointer와 stack pointer를 설정하며
함수의 코드에 따라 스택 프레임 안에서 실행한 다음 저장했던 리턴주소로 pop한다.
자세한건 어셈블리언어 포스팅에서 살펴보겠다.
.heap 영역
사용자가 malloc을 이용하여 원하는 만큼 할당하여 사용할 수 있는 영역이다.
memset
SYNOPSIS
함수 원형
: void *memset(void *b, int c, size_t len)함수 라이브러리
: #include <string.h>void *b
: 세팅할 메모리의 주소int c
: 세팅할 문자size_t len
: 세팅할 길이리턴값
: 세팅한 메모리의 첫번째 주소
DESCRIPTION
이 함수는 1바이트 단위로 세팅하기 때문에 c로 들어온 4바이트 중에서 위에 3바이트는 고려하지 않는다.
0같은 경우는 1바이트를 0으로 넣든 4바이트를 0으로 넣든 상관이없기 때문에 작동이 잘된다.
파라메터로 들어온 메모리의 주소부터 len으로 들어온 길이만큼 들어온 문자로 초기화
memset CODE
void *ft_memset(void *b, int c, size_t len)
{
while (len--)
*((unsigned char *)b + len) = (unsigned char)c;
return (b);
}
size_t
는 <stdlib.h>
헤더를 포함하면 사용할 수 있는 자료형이다.
이론상 가장 큰 사이즈를 담을 수 있는 unsigned 데이터 타입으로 정의할 수 있습니다.
32비트에서는 32비트 unsigned 정수형(int가 아님) 64비트에서는 64비트 unsigned 정수형이다.
bzero
SYNOPSIS
함수 원형
: void bzero(void *s, size_t n)함수 라이브러리
: #include <string.h>void *b
: 세팅할 메모리의 주소size_t len
: 세팅할 길이리턴값
: 없음
DESCRIPTION
파라메터로 들어온 메모리의 주소부터 len으로 들어온 길이만큼 0으로 초기화
bzero CODE
void ft_bzero(void *s, size_t n)
{
ft_memset(s, 0, n);
}
memset을 이용하여 0으로 초기화
memcpy
SYNOPSIS
함수 원형
: void *ft_memcpy(void *dst, const void *src, size_t n)함수 라이브러리
: #include <string.h>void *dst
: 복사가 될 메모리const void *src
: 복사할 값이 들어있는 메모리size_t n
: 복사할 개수리턴값
: dst의 시작주소
DESCRIPTION
src로 들어온 값을 n으로 들어온 값만큼 dst메모리에 복사
memcpy CODE
void *ft_memcpy(void *dst, const void *src, size_t n)
{
if (!dst && !src)
return ((void *)0);
while (n-- > 0)
*((unsigned char *)dst + n) = *((unsigned char *)src + n);
return (dst);
}
선언부에서 특이한게 있다면 const가 보인다.
const는 간단하게 얘기해서 변수를 상수로 만들어준다.
즉 변경할 수 없는 값으로 만들어준다는 얘기이다.
상수로 만들어주는 문법인 #define과 같다고 보면된다. #define보다는 const를 사용하는 것이 더 좋은 코딩습관이다.
우선 복사할 값과 복사받을 메모리가 모두 널 값으로 들어온다면 함수를 실행시킬 이유가없다.
dst의 시작주소를 반환해야하기 때문에 포인터를 변경하지 않게 코드를 작성했다.
unsigned char *형으로 형변환을 시켜준이유는 한 바이트 단위로 복사를 시켜주기 때문이다.
memccpy
SYNOPSIS
함수 원형
: void *memccpy(void *dst, const void *src, int c, size_t n)함수 라이브러리
: #include <string.h>void * dst
: 복사가 될 메모리const void * src
: 복사할 값이 들어있는 메모리size_t n
: 복사할 개수리턴값
: c를 만나면 그 다음 주소 못 만나면 NULL리턴
DESCRIPTION
src로 들어온 값을 n으로 들어온 값만큼 dst메모리에 복사하는데 복사 도중에 c를 만나면 종료
memccpy CODE
void *ft_memccpy(void *dst, const void *src, int c, size_t n)
{
size_t i;
i = 0;
while (i < n)
{
*((unsigned char *)dst + i) = *((unsigned char *)src + i);
if (*((unsigned char *)src + i) == (unsigned char)c)
return (dst + i + 1);
i++;
}
return (0);
}
딱히 설명할 부분은 없어보인다.
memmove
SYNOPSIS
함수 원형
: void *memmove(void *dst, const void *src, size_t len)함수 라이브러리
: #include <string.h>void *dst
: 복사가 될 메모리const void *src
: 복사할 값이 들어있는 메모리size_t n
: 복사할 개수리턴값
: dst의
DESCRIPTION
src로 들어온 값을 n으로 들어온 값만큼 dst메모리에 복사하는데 src와 dst의 메모리가 겹쳐도 수행해야한다.
memmove CODE
void *ft_memmove(void *dst, const void *src, size_t len)
{
char *dst_tmp;
const char *src_tmp;
if (!dst && !src)
return ((void *)0);
dst_tmp = dst;
src_tmp = src;
if (dst <= src)
while (len--)
*dst_tmp++ = *src_tmp++;
else
{
dst_tmp += len;
src_tmp += len;
while (len--)
*--dst_tmp = *--src_tmp;
}
return (dst);
}
memchr
SYNOPSIS
함수 원형
: void *ft_memchr(const void *s, int c, size_t n)함수 라이브러리
: #include <string.h>const void *s
: 비교를 진행할 메모리int c
: 비교할 값size_t n
: 비교할 개수리턴값
: c를 만나면 해당 주소 못 만나면 NULL리턴
DESCRIPTION
s가 가리키고 있는 메모리부터 시작해서 n개만큼 c가 있는지 검사한다.
memchr CODE
void *ft_memchr(const void *s, int c, size_t n)
{
size_t i;
i = 0;
while (i < n)
{
if (*((unsigned char *)s + i) == (unsigned char)c)
return ((void *)s + i);
i++;
}
return ((void *)0);
}
딱히 설명할 부분은 없어보인다.
memcmp
SYNOPSIS
함수 원형
: int ft_memcmp(const void *s1, const void *s2, size_t n)함수 라이브러리
: #include <string.h>const void *s1
: 비교를 진행할 메모리const void *s2
: 비교를 진행할 메모리size_t n
: 비교할 개수리턴값
: 검사 진행중에 다른 값이 나오면 *s1에서 *s2를 뺀 값, 검사 후에도 안나오면 0반환
DESCRIPTION
s1메모리와 s2메모리를 한 바이트씩 비교해서 다른 값이 나올 경우 *s1에서 *s2를 뺀 값을 리턴하고 종료
만약 끝까지 비교를 해도 다른 값을 찾지 못했다면 0을 반환한다.
memcmp CODE
int ft_memcmp(const void *s1, const void *s2, size_t n)
{
size_t i;
i = 0;
while (i < n)
{
if (*((unsigned char *)s1 + i) != *((unsigned char *)s2 + i))
return (*((unsigned char *)s1 + i) - *((unsigned char *)s2 + i));
i++;
}
return (0);
}
strcmp와 똑같은 원리이다.
다른 점은 memcmp는 중간에 0이 있어도 계속해서 검사를 진행하지만 strcmp는 함수를 종료한다.
그렇기 때문에 문자열을 비교한다면 strcmp를 문자열이 아닌 요소를 비교한다면 memcmp를 사용한다.