항목 2에서 "메모리를 직접 제어하여, 사용할 때는, 범위 안전성을 제공하는 함수만을 사용해야 한다"는 교훈을 얻을 수 있었다. 이번 항목에서는 문자열 포매팅에 있어서, 그 대안들을 논쟁해 본다.

질문

1. 다음의 sprintf 대안들의 장단점을, 이전의 항목 2에서 나왔던 분석과 예제코드를 이용해서 비교, 대조하라.

ⓐ snprintf

sprintf 와 가장 근접한것이 snprintf 일 것이다. snprintf 는 출력 버퍼의 크기를 지정함으로써, 범위를 지정해 안전성을 확보한 함수인 것이다. sprintf 의 단점을 너무나 잘 알았던 컴파일러 제공사들은 비표준으로 이런 함수를 제공하고 있었다. 그러다 C99에서부터 공식적으로 표준 함수가 되었다.

가장 위험한것은 고쳤지만, 형식에 대한 안전성을 고치지 못했다.  저번 항목의 규칙대로 정리 하자면,

표준이며, 사용하고 편하고, 효율적이고, 안정적이지만, 형식에선 불안하고, 템플릿 안에서 사용할수 없다.

가이드 라인 : 절대 sprintf는 절대 사용 하지 말것


ⓑ std::stringstream

이게 무엇인지는 우선 다음 링크에서 참조해야 할 것이다. 나도 이 라이브러리(?)를 최근에 알았기에, 요즘은 이것만 쓰고 있다. 링크 : stringstream 예제

예제를 보면 알겠지만, .. 이것을 분석해 보면

표준이며, 사용하기 불편하고, 비효율적이지만, 길이에 안정적이며, 형식에 안정적이고, 템플릿 안에서 사용 할 수 있다. 아참 이것은 C++ 03 표준이다.


ⓒ std::strstream

우선 설명해야 하는것은 이 객체는 C++ 03 부터 폐기 되었다. ... 그렇다면 왜 언급을 하고 있을까? stringstream과 사용 방법이 거의 동일한데, 다른점이 있다면, 출력 버퍼를 직접 사용한다. 이것은 다음 과 같이 분석 된다.

표준이며, 사용하기 불편하지만, 효율적이고, 길이에 안정적이며, 형식에 안정적이고 템플릿 안에서 사용 할 수 있다. .. ... 폐기 된 녀석이, 최신것보다 좋은 점수를 받고 있다니 ...


ⓓ boost::lexical_cast

여기서 boost를 설명하기도 그렇고, boost::lexical_cast 사용법을 설명하는것도 맞지 않다. 분석만 하자면,

비표준이고, 효율적이지 않지만, 사용하기 쉽고, 길이에 안정적이며, 형식에 안정적이고 템플릿 안에서 사용 될 수 있다.


총평

하나의 값을 그냥 문자열로 변환하기만 하면 된다면, boost::lexical_cast 를 선호 할 것

단순한 포매팅이 필요하거나, 넓은 문자열이나 템플릿화가 필요하다면, stringstream 이나 strstream 을 선호 할것

좀 더 복잡한 포매팅이 필요하며, 넓은 문자열이나 템플릿화가 필요하다면, snprintf를 선호 할것

다른 모든 대안들이 모두 코드의 지점에서 성능을 크게 떨어뜨리는 병목으로 작용한다면, snprintf 나 stringstream 보다 더 빠른것을 선호 할것

마지막으로, 절대 sprintf는 사용하지 말 것. 

MSVC2005 를 쓴다면, _s 라 든지 _s_l 같은 함수들을 지원해 주고 있으니, 한번 써보는것도 괜찮을 듯 싶다. :) 아니면 직접 만들던가.


posted by 농사를 짓는 게임 프로그래머 최익필

댓글을 달아 주세요