2008/04/22 23:41
snprintf()
대학시절 해킹 동아리를 하면서 생긴 좋은 습관 하나는, strcpy(), strcat(), sprintf() 같은 함수는 거들떠도 안본다는 것이다. 무조건 이른바 “n계열”인 strncpy(), strncat(), snprintf()만 사용한다. 그런데 사실 이게 또 좀 오묘한게 세 함수의 동작방식이 모두 다르다.(KLDP의 관련쓰레드)
간단하게 요약하자면 strncpy()는 버퍼 길이까지(무조건!) 씀. strncat()은 문자열 길이 기준. snprintf()는 무조건 NULL-terminate 정도. 대개 strncat()은 쓰지 않으니, strncpy()는 NULL-terminate되지 않을 수 있다는 점만 명심하고 쓰면 되겠다.
또 헷갈리기 쉬운 것은, 다른 xxxprintf() 함수들이 모두 쓰여진 글자 수를 리턴하는 데 반해, snprintf()는 ‘버퍼가 충분했을 경우 쓰여졌을’ 글자 수를 리턴한다는 거다. 예를 들어, snprintf(NULL,0,”format”,...) 으로 필요한 문자열 버퍼의 크기를 미리 계산해볼 수도 있다.
sprintf()와 snprintf()의 또 다른 차이로 (요건 glibc에서만 그럴 지도 모르겠다만..) sprintf()는 sprintf(buffer, “%s...”,buffer) 와 같이 쓸 수 있는 반면, snprintf()는 snprintf(buffer, size, “%s...”,buffer) 와 같이 쓸 수 없다.
snprintf()를 써서 정수배열을 문자열로 바꾸는 함수를 생각해보면..
int list2str(int *list, int list_size, char *buffer, int buffer_size)
{
int i;
int length, thisLength;
if( 0 == buffer_size )
return 0;
if( 0 == list_size ) {
buffer[0] = ‘\0’;
return 0;
}
for(i = 0, length = 0; i < list_size; i++) {
thisLength = snprintf( buffer + length, buffer_size - length, “%s%d”, 0 == i ? “”:”,”, list[i] );
if( thisLength > buffer_size - length ) { // 이렇게 bound check..
buffer[length] = ‘\0’;
return i;
}
length += thisLength; // 나중에 수정;;
}
return i;
}
대강 이렇게 되지 않을까...
첨언하자면, printf() 시리즈의 엽기적 기능 중 하나로 ‘%n’이란 게 있다. 수많은 해커들이 format string 공격을 위해 애용해온 기능이다. 요건 특이하게도 뒤에 지정한 parameter를 output parameter로 이용하는데, %n위치까지의 문자열 길이를 해당 변수에 저장해준다. 즉,
len = snprintf(NULL,0,”format”,...)
snprintf(NULL,0,”format%n”,&len)
은 동일한 결과를 준다는 거.. 물론 len이 int여야하지만...
자꾸 까먹는 것 같아서 정리해본다. 문자열 buffer size 신경쓰기 싫다 ㅠㅠ
TAG 프로그래밍





댓글을 달아 주세요
횽아 다 좋은데..
length 값 증가시키는 코드가 안보임.
for 문 안에 length += thisLength 추가하면 될 듯.
앗 그렇군 ㅋㅋㅋ 수정했다능;;
strncpy는 복사하고 남은 영역을 전부 0으로 패딩한다는 것도 주의할 점. 예외적으로 큰 문자열 때문에 버퍼 크게 잡아놓고 매번 strncpy 해버리면 성능이 거시기 해짐.
그쵸.. strcpy를 strncpy로 무작정 바꾸면 새된다는 거... ㄱ-