2017-12-23 50 views
1

부호가없는 32 비트 정수로 압축 된 짧은 문자열/문자 배열은 여러 가지 이유로 단순한 정수 비교와 한 번에 비교할 수 있고 여전히 인간의 비트를 유지하면서 switch 문에서 사용할 수 있기 때문에 매우 유용합니다. 가독성.짧은 문자열을 32 비트 정수로 변환하는 가장 효율적인 방법은 무엇입니까?

32 비트 정수로 이러한 짧은 문자열을 변환하는 가장 일반적인 방법은 이동하는 것입니다/또는 : 너무 긴

#include <stdint.h> 

uint32_t quadchar(const char* _str) 
{ 

    uint32_t result = 0; 

    for(size_t i=0; i<4; i++) 
    { 
     if(_str[i] == 0) 
      return result; 
     result = (result << 8) | _str[i]; 
    } 

    return result; 
} 

문자열이, 잘립니다.

지금까지는 그렇게 좋았지 만 런타임에는 약간의 시간이 소요되었습니다. 컴파일시에도이 작업을 수행 할 수 있습니까?

+2

C++ 14 이상에서는 함수에'constexpr'을 추가하면됩니다. C++ 11에서 이것을 어떻게 (즉 재귀 적으로) 수행하는지 보여주는 해답이 이미 있습니다. C++ 03의 경우 좋은 구문을 얻는 것이 사실상 불가능하지만, C++ 03 솔루션은 일부 스크립팅을 통한 소스 코드 전처리입니다. –

+0

union 메서드는 정의되지 않은 동작이며 결과는 CPU의 endianness에 따라 다릅니다. – Barmar

+0

@Barmar : true, thx. 나는이 구절을 삭제했다. – user2328447

답변

0

C++ 11부터는 constexpr specifier을 사용하여 런타임시 비용이 전혀 들지 않으면 서 컴파일 할 때이 작업을 수행 할 수 있습니다.

namespace Internal 
{ 
    uint32_t inline constexpr quadchar(char const *_input, 
     uint8_t _idx, uint32_t _result) 
    { 
     return _idx == 4 ? _result 
      : *_input ? quadchar (_input+1, _idx + 1, (_result << 8) | *_input) 
       : _result; 
    } 
} 

uint32_t inline constexpr quadchar(char const *_input) { 
    return Internal::quadchar(_input, 0, 0); 
} 

구현 오버로드를 내부 네임 스페이스에 배치하여 사용자로부터 숨 깁니다. 구문은 위의 런타임 예제에서와 같이 멋지지 않습니다. 왜냐하면 constexprif을 사용할 수 없기 때문입니다.하지만 그만한 가치가 있다고 생각합니다.

+0

질문에 적용된 것과 동일한 이식성 경고가이 대답에 적용됩니다.변환 된 문자열이 네트워크를 통해 지속되거나 전송되지 않으면 문제가되지 않을 수 있습니다. 'honl()'에 대한 호출은 여기에서 현명 할 수 있습니다. 많은 CPU에서 아주 적은 명령어로 컴파일됩니다. – marko

+2

죄송합니다, 무슨 뜻인지 정확히 이해하지 못합니다. 여기서 이식 할 수없는 것은 무엇입니까? 내가 볼 수있는 한 모든 것은 이식 가능해야하며, 엔디안에 의존하지 않아야합니다. 'honl() '은 무엇입니까? 그것에 대해 아무 것도 찾을 수 없습니다. – user2328447

1

세부 도우미 기능이 필요하지 않습니다. 기본값을 사용할 수 있습니다.

그리고 이중 삼항 연산자에 대한 필요가 없습니다 : 단일 테스트

std::uint32_t inline constexpr quadchar (char const * input, 
             std::size_t idx = 0U, 
             std::uint32_t result = 0U) 
{ 
    return (idx < 4U) && *input 
     ? quadchar(input+1, idx+1U, (result << 8) | *input) 
     : result; 
} 

모든 만들 수 있습니다, 그것은 좀 더 휴대용 및 일반 만들기 위해, 나는)

1 제안 idx 제한

2) result 변화에 대한 CHAR_BIT 대신 8을 사용하기위한 sizeof() 대신 4을 사용 ("를 포함하는 기억")

result 유형의 템플릿 유형 (기본값은 std::uint32_t)을 사용하십시오.

당신이 std::uint32_t을 할 때 당신이

constexpr auto u32 = ichar(ptr); 

를 호출 할 수 있습니다

template <typename I = std::uint32_t> 
constexpr inline I ichar (char const * input, 
          I result = 0U, 
          std::size_t idx = 0U) 
{ 
    return (idx < sizeof(I)) && *input 
     ? ichar(input+1, idx+1U, (result << CHAR_BIT) | *input) 
     : result; 
} 

같은

뭔가, 또는 다른 반환 유형

constexpr auto u64 = ichar<std::uint64_t>(ptr); 

(예에 의해).

+0

고맙습니다. 'sizeof()'와 템플릿 아이디어는 매우 좋다. 'CHAR_BIT'에 대해서는 그렇게 확신하지 못합니다. 'CHAR_BIT'! = 8 인 경우 결과는 다른 시프 팅 때문에 8 비트 char의 결과와 다를 것입니다. 나는 이것이 더 많은 것 대신에 덜 이식성이 있다고 생각한다. 아마도 입력 char 대신에 추가로 & & 0xff를하는 것이 더 나을 것입니다. 도우미 함수는'result'와'input' 매개 변수를 감추기 위해 구현되었습니다. 왜냐하면 그것들은 사용자에게 이해가되지 않기 때문입니다. 물론 기본 매개 변수도 괜찮습니다. – user2328447

+0

@ user2328447 -'CHAR_BIT = 12 '가있는 플랫폼에'std :: uint32_t'가 존재합니까?)하지만'CHAR_BIT> 8'('8 '가 최소값),'input'의 모든 문자는'CHAR_BIT' 비트와 같습니다; 그래서'(결과 << 8) | * input' 당신은 앞의 char에서 마지막 비트와'* input'에서 첫 번째 비트의 충돌 (또는 bitted)을가집니다. – max66

+0

@ user2328447 - 예 : '& 0xff'아이디어는 좋은 대체 솔루션이 될 수 있습니다. 이런 방식으로, 문자 (CHAR_BITS> 8의 경우)에서 일부 비트의 사용을 느슨하게하고'입력 '문자의 오른쪽 비트를 관리하는 것이 어려울 수 있으며 플랫폼에 따라 다를 수 있습니다. – max66