2011-01-18 3 views
6

unsigned short를 char *로 변환 (즉, 25를 '25'로 변환)하는 것은 효율적이고 이식 가능한 방법은 무엇입니까?부호없는 short를 char *로 효율적으로 변환 *

나는 (std :: string) 문자열을 가져 오는 것과 같은 것을 피하고 싶습니다. 이 변환은 신속하고 자주 발생해야하기 때문에 성능이 중요합니다.

저는 sprintf를 사용하는 것과 같은 것을 찾고 있었지만 어떤 아이디어라도 탐색기에 넣고 싶습니다.

+3

이 사용 해봤' sprintf' /'snprintf'? 코드를 프로파일 링하고 이것이 성능 핫스팟이라고 결정 했습니까? –

+15

아래에 링크 된 기사 하단의 표는 구현의 효율성과 최적성에 관한 한 stdlib 구현이 어디에 위치 하는지를 명확하게 보여줍니다. http://www.codeproject.com/KB/recipes/Tokenizer.aspx –

답변

6

먼저 해보고 빨리 해보십시오. 특정 코드가 성능이 좋지 않다는 것을 확실히 볼 수있는 경우에만 최적화하십시오.

snprintf() 버퍼로 원하는 것을 할 수 있습니다. 가능한 가장 빠른 솔루션입니까? 전혀. 그러나 가장 간단한 방법 중 하나는 코드를 작동 상태로 만드는 것입니다. 여기에서 snprintf()에 대한 호출이 매우 힘들어서 최적화해야하는 경우, 다음으로 만 빠른 솔루션을 찾으십시오.

1

적어도 sprintf를 시도해보고 C++로 태그를 지정 했으므로 StringStream을 시도하고 실제로 프로필을 작성하십시오. 많은 경우 컴파일러는 꽤 잘 작동하는 것을 만들기에 충분히 똑똑합니다. 병목 현상이 될 것이라는 것을 알고있을 때만 실제로 더 빠른 방법을 찾아야합니다.

2

문자열의 배열 등 아마

array[25] = "25"; 
array[26] = "26"; 

array[255] = "255"; 

인가? 아주 쉽게 테이블 소스 코드를 생성하는 작은 프로그램을 작성한 다음 프로젝트에서이 파일을 사용할 수 있습니다.

편집 : 나는 당신이 의미하는 것을 얻지 못한다.

+0

문자열로 생각합니다. 그들은 "std :: string"을 의미합니다. 나는 그것도 혼란스러워했다. – gravitron

1

이 시도 :

int convert(unsigned short val, char* dest) 
{ 
    int i = 0; 
    if (val > 10000) 
    { 
    dest[i++] = (val/10000) | 0x30; 
    val %= 10000; 
    } 
    if (val > 1000) 
    { 
    dest[i++] = (val/1000) | 0x30; 
    val %= 1000; 
    } 
    if (val > 100) 
    { 
    dest[i++] = (val/100) | 0x30; 
    val %= 100; 
    } 
    if (val > 10) 
    { 
    dest[i++] = (val/10) | 0x30; 
    val %= 10; 
    } 
    dest[i++] = (val) | 0x30; 
    dest[i] = 0; 
    return i; 
} 
+1

아마도 마지막'dest [i] = '\ 0';'? –

+0

@Tony, oops - 잘 잡으세요! – Nim

1
내가 여기 함께 다양한 기능의 테스트를 해킹하고, 이것이 내가 생각 해낸 것입니다

:

write_ushort : 7.81의
uShortToStr : 8.16의
변환 : 6.71s
use_sprintf : 49.66s

(Write_ushort는 제 버전으로, p 마이크로 최적화보다는 ossible을 사용하여 주어진 문자 버퍼로 형식화합니다. use_sprintf는 명백한 sprintf (buf, "% d", x)이며 다른 것은 없습니다. 나머지 두 개는 다른 답변에서 가져온 것입니다.)

이것은 꽤 놀라운 차이입니다. sprintf를 거의 모든 차별화 된 순서로 사용하는 것을 누가 생각할 것입니까? 오, 예, 테스트 된 각 함수를 몇 번 반복 했습니까?

// Taken directly from my hacked up test, but should be clear. 
// Compiled with gcc 4.4.3 and -O2. This test is interesting, but not authoritative. 
int main() { 
    using namespace std; 
    char buf[100]; 

#define G2(NAME,STMT) \ 
    { \ 
    clock_t begin = clock(); \ 
    for (int count = 0; count < 3000; ++count) { \ 
     for (unsigned x = 0; x <= USHRT_MAX; ++x) { \ 
     NAME(x, buf, sizeof buf); \ 
     } \ 
    } \ 
    clock_t end = clock(); \ 
    STMT \ 
    } 
#define G(NAME) G2(NAME,) G2(NAME,cout << #NAME ": " << double(end - begin)/CLOCKS_PER_SEC << " s\n";) 
    G(write_ushort) 
    G(uShortToStr) 
    G(convert) 
    G(use_sprintf) 
#undef G 
#undef G2 

    return 0; 
} 

sprintf를 내 ~ 5 살짜리 노트북, 평균 전환 당 약 0.25 μs의 다시 2999 번 이상을 전체 범위를 한 다음, 부호 없음 short의 전체 가능한 범위를 변환.

Sprintf는 휴대용입니다. 그것은 또한 귀하의 요구 사항에 대해 충분히 효율적입니까?


내 버전 :

// Returns number of non-null bytes written, or would be written. 
// If ret is null, does not write anything; otherwise retlen is the length of 
// ret, and must include space for the number plus a terminating null. 
int write_ushort(unsigned short x, char *ret, int retlen) { 
    assert(!ret || retlen >= 1); 

    char s[uint_width_10<USHRT_MAX>::value]; // easy implementation agnosticism 
    char *n = s; 
    if (x == 0) { 
    *n++ = '0'; 
    } 
    else while (x != 0) { 
    *n++ = '0' + x % 10; 
    x /= 10; 
    } 

    int const digits = n - s; 
    if (ret) { 
    // not needed by checking retlen and only writing to available space 
    //assert(retlen >= digits + 1); 

    while (--retlen && n != s) { 
     *ret++ = *--n; 
    } 
    *ret = '\0'; 
    } 
    return digits; 
} 

컴파일 시간 그것이 내가 무엇을 사용 때문에 TMP 기능은 아무것도 새로운,하지만 완전한 예제를 포함하지 않습니다 로그 :

template<unsigned N> 
struct uint_width_10_nonzero { 
    enum { value = uint_width_10_nonzero<N/10>::value + 1 }; 
}; 
template<> 
struct uint_width_10_nonzero<0> { 
    enum { value = 0 }; 
}; 
template<unsigned N> 
struct uint_width_10 { 
    enum { value = uint_width_10_nonzero<N>::value }; 
}; 
template<> 
struct uint_width_10<0> { 
    enum { value = 1 }; 
}; 
+0

실제로 그 차이는 놀랍지 않습니다. sprintf는 다양한 형식 지정자를 가질 수 있습니다 ... 알고리즘에서 고려해야 할 사람이있을 수 있습니다. sprintf 나 심지어는 좀 더 느린 짐승 같은 것을 보지 못했습니다. 대부분의 경우 최적화할만한 가치가없는 프로필에서 실행 시간의 상당 부분을 차지하는 boost :: format과 같습니다. –

+0

작은 천사가이 게시물에 풍자를 사용하지 말자고 누군가가 그것에 대해 의견을 말하게되었습니다. 나는 듣지 않았다. 이 기능은 거의 2 억 번 (USHRT_MAX, 여기 65,535, * 3,000) 실행되기 때문에 큰 차이가있는 것처럼 보입니다. @ ÖöTiib : 프로파일 작성자를 사용하지 않고 OP를 보여준 결론을 다시 한 번 나타내 보았습니다. 프로파일 작성을 위해 OP 코드에 액세스 할 수 없기 때문에 다시 말 했습니다. –

+0

예,하지만 솔루션을 제공했습니다. 왜냐하면 ... 누가 알기 때문입니다. 진짜 문제가 보이지 않으면 냉소적이어서는 안됩니다. 어떤 이유로 텍스트 기반 인터페이스와 프로토콜이 인기를 얻었고 두 모듈이 sprintf를 사용하여 수백만 개의 서명되지 않은 단락을 서로에게 말하면 병목이 될 수 있습니다. 나는 물론 그러한 경우에 바이너리 인터페이스/프로토콜로 전환하는 것을 선호 할 것이지만 재검토 인터페이스는 다른 이유로 인해 비싸거나 문제가 될 수있다. –

관련 문제