대체로 남들이 짜놓은 코드만 바라보다 보니, 막상 직접 짜게되니까 부딪치는 문제들이 다발하기 시작했다. 백문이 불여일타라고 했던가. 아무리 코드를 계속 보아도 실제 쳐보는 것과는 판이하게 다르더라.
학부때 당연하게 사용했던 메모리 초기화까지도 이제는 가물가물해졌다.
memcpy(&a, 0, sizeof(a));
이렇게 해놓고 자꾸 segmentation fault가 나는 원인을 찾아보겠다고 한동안 계속 삽질을 하였다.
참 어이없는 실수가 아닐 수 없지만 오랜만에 직접짜다 보니 이런 일이 계속 생긴다.
위 memcpy는 0으로 초기화하는 것이 아닌 0번 주소부터 변수 a 크기만큼 복사를 해 오는 것이다. 0번 주소는 일반 application이 접근할 수 없는 주소라 접근하는 순간 죽어버린다.
memset(&a, 0, sizeof(a));
관련된 일을 하는 사람들이라면 memset이 올바른 초기화 함수라는 것을 알고 있을 것이다.
memset- fill memory with a constant byte
manpage에 정의된 memset의 설명은 사실 초기화라는 부분은 언급되어 있지 않고, 주어진 상수값으로 특정 범위의 메모리를 채워넣는 것으로 되어 있다. 즉 우리는 보통 0이라는 상수로 특정 범위의 메모리를 채워 넣음으로써 흔히 특정 변수의 메모리를 초기화하게 되는 것이다.
보통쓰는 0으로 초기화하는 것은 알겠는데 1로 초기화하려면 어떻게 하면 될까?
사실 1로 초기화하는 경우는 거의 없어서 별 쓸모는 없을지 모르겠지만 한번 해봤다.
memset(&a, 1, sizeof(a))
위와 같이 0을 1로 바꾸면 되는 것인가? 해보니 아래와 같은 결과가 나왔다.
[예상 결과]
1111 1111 1111 1111
[실제 결과]
0000 0001 0000 0001
단순히 채워 넣을 상수로 1을 넘겨주면 1111 1111 1111 1111으로 초기화되는 것이 아니라 0000 0001 0000 0001로 해당 메모리가 set되게 된다. 순간 내가 memset에 대해 잘못 이해하고 있음을 알았다.
그렇다면 1111 1111 1111 1111으로 초기화하려면 어떻게 해야 하는 것인가?
Set as "0xFF"
1111 1111 1111 1111
혹은
Set as "255"
1111 1111 1111 1111
위와 같이 넘겨주어야 한다.
memset의 definition을 보면 아래와 같다.
void *memset(void *s, int c, size_t n);
constant byte 부분이 int c인데 integer로 선언되어 있어 4byte 크기를 가지고 있다. 이중 하위 1byte를 사용하여 메모리를 채워넣기 되어 있다.
0이 아닌 값으로 메모리를 채워넣을 일은 거의 없겠지만 0이 아닌 이외의 값으로 채워 넣을 계획이라면 memset에 넣어 주어야 할 값이 integer 하위 1 byte pattern이라는 것을 고려하여 잘 계산해서 넣어야 겠다.
아래 몇가지 더 테스트 한 결과는 다음과 같다.
[결과는 이진수 표현]
Set as "0"
0000 0000 0000 0000
Set as "0x0"
0000 0000 0000 0000
Set as "1"
0000 0001 0000 0001
Set as "0x1"
0000 0001 0000 0001
Set as "0xF"
0000 1111 0000 1111
Set as "0xFF"
1111 1111 1111 1111
Set as "255"
1111 1111 1111 1111
[참고용 manpage]
[댓글에서 자연&사람 님께서 지적해주셔서 올바르게 다시 수정하였습니다. 감사합니다.]
'Language > C' 카테고리의 다른 글
Signed / Unsigned 의 비교 (0) | 2019.08.24 |
---|---|
Type casting 시 주의해야할 점. (signed, unsigned) (0) | 2016.07.04 |
sizeof - 함수가 아닌 연산자. (0) | 2016.07.04 |