반응형
strcpy 를 사용할 때 그 변수의 사이즈에 대하여 정확히 인지를 하고 사용해야 한다. 자칫 잘못하면 엄한 메모리의 영역까지 엎어칠 수 있다.
다음의 예제는 a 라는 스트링 변수에 문자를 2 byte만 넣을 수 있는데 이것을 오버하여 무턱대고 strcpy 를 했을 때 그 뒤에 바로 따라오는 변수 b의 기존 값(12345)이 뭉개져 버리는 것을 보여주고 있다.
출력 결과는 다음과 같이 원래 있는 b 변수의 값이 12345 였으나 a 변수에 사이즈 보다 큰 값을 strcpy 하는 순간 b변수 영역까지 엎어쳐서 b변수의 값이 변경되어 보인다.
b 변수의 값이 뭉개진 후에는 strlen(b) 한 값이 정상값 5가 15로 늘어나면서 sizeof(b) 한 10 보다 더 커져 버린 것까지 적나라하게 보여주고 있다.
이러한 문제를 해결하기 위하여 strncpy 를 사용하여 target 변수의 사이즈만큼만 strcpy 하는 것을 권장한다.
매번 프로그램에서 strncpy 를 사용하면서 뒤에 sizeof 해서 크기를 넣기가 귀찮다면 매크로로 wrapping 해서 사용할 수도 있다.
여기서 굳이 do .. while 로 묶어 준 것은 STRCPY(a, b) 한 뒤에 세미콜론 (;) 문자를 기술하지 않으면 컴파일시에 오류가 나도록 하기 위함이다. 어느 문장은 세미콜론(;) 이 있고 어느 문장은 세미콜론(;) 이 없다면 혼란스러우니 일관성있게 모두 문장의 끝에는 세미콜론(;) 을 찍도록 표준화하기 위한 꼼수인 것이다.
strncpy 의 이해
그렇다면 strncpy를 사용할 때의 위험성은 없을까? 정확히 이해하지 못 하고 사용한다면 원하는 결과를 얻을 수 없기는 마찬가지이다.
strcpy( name, "최성환");
strncpy( name, "ab", 2 );
name을 출력해 보면 결과는 [ab] 일까 [ab성환] 일까. 결과는 [ab성환] 이다. 그렇다면 [ab]라는 결과를 얻고 싶다면 어떻게 해야 할까?
strncpy( name, "ab", 3 ); 또는 strncpy( name, "ab", sizeof("ab")); 을 하면 된다. 즉 "ab"문자열 뒤에 있는 NULL 문자까지 같이 복사해 줘야 하는 것이다.
strcpy는 자동으로 마지막의 null 문자까지 복사해 주는 반면에 strncpy는 정확히 뒤에 지정한 길이만큼만 복사해 주기 때문이다.
보통의 경우 strncpy를 사용할 때 복사하는 길이를 target 변수의 사이즈대로 하게 된다. 하지만 target 변수의 길이가 작을 경우에는 반드시 마지막에 null 문자를 강제로 세트하는 로직이 필요한 것이다. 위의 매크로 예제 처럼 말이다.
다음의 예제는 a 라는 스트링 변수에 문자를 2 byte만 넣을 수 있는데 이것을 오버하여 무턱대고 strcpy 를 했을 때 그 뒤에 바로 따라오는 변수 b의 기존 값(12345)이 뭉개져 버리는 것을 보여주고 있다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct a {
char a[3];
char b[10];
} a_t;
main() {
a_t a;
strcpy( a.b, "12345" );
printf("b ptr=[%p] len=[%ld] size=[%ld] value=[%s]\n",
a.b, strlen(a.b), sizeof(a.b), a.b );
strcpy( a.a, "123456789012345678" );
printf("b ptr=[%p] len=[%ld] size=[%ld] value=[%s]\n",
a.b, strlen(a.b), sizeof(a.b), a.b );
};
#include <stdlib.h>
#include <string.h>
typedef struct a {
char a[3];
char b[10];
} a_t;
main() {
a_t a;
strcpy( a.b, "12345" );
printf("b ptr=[%p] len=[%ld] size=[%ld] value=[%s]\n",
a.b, strlen(a.b), sizeof(a.b), a.b );
strcpy( a.a, "123456789012345678" );
printf("b ptr=[%p] len=[%ld] size=[%ld] value=[%s]\n",
a.b, strlen(a.b), sizeof(a.b), a.b );
};
출력 결과는 다음과 같이 원래 있는 b 변수의 값이 12345 였으나 a 변수에 사이즈 보다 큰 값을 strcpy 하는 순간 b변수 영역까지 엎어쳐서 b변수의 값이 변경되어 보인다.
b ptr=[0022FF63] len=[5] size=[10] value=[12345]
b ptr=[0022FF63] len=[15] size=[10] value=[456789012345678]
b ptr=[0022FF63] len=[15] size=[10] value=[456789012345678]
b 변수의 값이 뭉개진 후에는 strlen(b) 한 값이 정상값 5가 15로 늘어나면서 sizeof(b) 한 10 보다 더 커져 버린 것까지 적나라하게 보여주고 있다.
이러한 문제를 해결하기 위하여 strncpy 를 사용하여 target 변수의 사이즈만큼만 strcpy 하는 것을 권장한다.
strncpy( a.a, "123456789012345678", sizeof(a.a) );
매번 프로그램에서 strncpy 를 사용하면서 뒤에 sizeof 해서 크기를 넣기가 귀찮다면 매크로로 wrapping 해서 사용할 수도 있다.
#define STRCPY(_dest, _src) \
do { \
long _isz; \
\
_isz = sizeof(_dest) - 1; \
if(_isz < 0) \
_isz = 0; \
\
strncpy(_dest, _src, _isz); \
_dest [_isz] = (char) 0; \
} while(0)
do { \
long _isz; \
\
_isz = sizeof(_dest) - 1; \
if(_isz < 0) \
_isz = 0; \
\
strncpy(_dest, _src, _isz); \
_dest [_isz] = (char) 0; \
} while(0)
여기서 굳이 do .. while 로 묶어 준 것은 STRCPY(a, b) 한 뒤에 세미콜론 (;) 문자를 기술하지 않으면 컴파일시에 오류가 나도록 하기 위함이다. 어느 문장은 세미콜론(;) 이 있고 어느 문장은 세미콜론(;) 이 없다면 혼란스러우니 일관성있게 모두 문장의 끝에는 세미콜론(;) 을 찍도록 표준화하기 위한 꼼수인 것이다.
strncpy 의 이해
그렇다면 strncpy를 사용할 때의 위험성은 없을까? 정확히 이해하지 못 하고 사용한다면 원하는 결과를 얻을 수 없기는 마찬가지이다.
strcpy( name, "최성환");
strncpy( name, "ab", 2 );
name을 출력해 보면 결과는 [ab] 일까 [ab성환] 일까. 결과는 [ab성환] 이다. 그렇다면 [ab]라는 결과를 얻고 싶다면 어떻게 해야 할까?
strncpy( name, "ab", 3 ); 또는 strncpy( name, "ab", sizeof("ab")); 을 하면 된다. 즉 "ab"문자열 뒤에 있는 NULL 문자까지 같이 복사해 줘야 하는 것이다.
strcpy는 자동으로 마지막의 null 문자까지 복사해 주는 반면에 strncpy는 정확히 뒤에 지정한 길이만큼만 복사해 주기 때문이다.
보통의 경우 strncpy를 사용할 때 복사하는 길이를 target 변수의 사이즈대로 하게 된다. 하지만 target 변수의 길이가 작을 경우에는 반드시 마지막에 null 문자를 강제로 세트하는 로직이 필요한 것이다. 위의 매크로 예제 처럼 말이다.
반응형
'컴퓨터활용 > 유닉스' 카테고리의 다른 글
정적 라이브러리, 공유 라이브러리, 동적 적재 라이브러리 (0) | 2008.10.01 |
---|---|
외부 binary 링크하여 컴파일하기 (0) | 2008.09.19 |
전각 문자를 반각 문자로 변환하는 C 프로그램 (0) | 2008.07.14 |
대소문자로 변환 쉘 (1) | 2008.07.02 |
멀쩡한 쉘이 실행이 안 되고 파일이 없다고 메시지가 나온다면.. (1) | 2008.06.27 |