[C/C++] C int형 배열 memset 사용 시 주의사항

pikamon·2022년 5월 15일
0

C/C++

목록 보기
3/9

일반적으로 memset은 배열의 모든 원소를 특정 값으로 초기화하기 위해 사용된다. 문제는 memset은 byte 크기의 배열을 대상으로 사용해야 한다는 점이다.

short나 int형 배열을 대상으로 memset을 사용할 때는 0 또는 -1로 초기화할 때만 사용하여야 한다.

왜냐면 memset 함수의 구현을 보면 알 수 있다.

1. memset 함수 구조

우리가 memset을 사용할 때를 잘 떠올려보면, 배열 원소의 타입 정보를 입력으로 전혀 받지 않는 것을 알 수 있다.

string.h 안에 정의된 memset 함수를 보자.

void *memset(void *dest, int c, size_t count);

배열의 주소를 void 포인터로 받고, 무슨 타입인지 안알려주게끔 되어있다.

왜지?

libgcc/memset.c 안에 정의된 memset 함수의 소스 코드를 보자.

  • memset.c
#include <stddef.h>

void *memset(void *dest, int val, size_t len)
{
	unsigned char *ptr = dest;
	while (len-- > 0)
		*ptr++ = val;
	return dest;
}

배열의 주소를 unsigned char형으로 변환하여 순회하는 것을 볼 수 있다.

에라이..

만약 int 타입의 배열을 입력으로 주면 4바이트 공간 내에 1바이트마다 val의 값이 들어간다는 뜻이 된다.

그러면 val이 오직 0 또는 -1일 때만 값이 정상적으로 들어가며, 나머지는 보장되지 않는다.

예를 들어 val의 값이 1이고 int형 배열을 초기화한다고 할 때, 우리가 원하는 결과는 아래겠지만,

ex) val = 1, 원하는 결과
00000000 00000000 00000000 00000001 = 1
                                ^^^
                                val

실제 결과는 아래와 같이 전혀 엉뚱한 값이 들어간다는 뜻이다.

ex) val = 1, 실제 결과
00000001 00000001 00000001 00000001 = 16843009
     ^^^      ^^^      ^^^      ^^^
     val      val      val      val

2. 대책

그러면 (unsigned) char 이외의 배열은 어떻게 초기화하면 될까?

스택 오버플로우에서 말하길, 그냥 for문 돌리면 된다고 한다.

왜냐면 memset 구현 자체가 for문이기 때문이다. (충격)

profile
개발자입니당 *^^* 깃허브 https://github.com/pikamonvvs

0개의 댓글