일반적으로 memset은 배열의 모든 원소를 특정 값으로 초기화하기 위해 사용된다. 문제는 memset은 byte 크기의 배열을 대상으로 사용해야 한다는 점이다.
short나 int형 배열을 대상으로 memset을 사용할 때는 0 또는 -1로 초기화할 때만 사용하여야 한다.
왜냐면 memset 함수의 구현을 보면 알 수 있다.
우리가 memset을 사용할 때를 잘 떠올려보면, 배열 원소의 타입 정보를 입력으로 전혀 받지 않는 것을 알 수 있다.
string.h 안에 정의된 memset 함수를 보자.
void *memset(void *dest, int c, size_t count);
배열의 주소를 void 포인터로 받고, 무슨 타입인지 안알려주게끔 되어있다.
왜지?
libgcc/memset.c 안에 정의된 memset 함수의 소스 코드를 보자.
#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
그러면 (unsigned) char 이외의 배열은 어떻게 초기화하면 될까?
스택 오버플로우에서 말하길, 그냥 for문 돌리면 된다고 한다.
왜냐면 memset 구현 자체가 for문이기 때문이다. (충격)