2013-10-14 4 views
4

여기 std::codecvt_utf8<> 패싯을 사용하여 wchar_t을 UTF-8로 변환하는 코드 스 니펫입니다. Visual Studio 2012를 사용하면 기대치가 충족되지 않습니다 (코드 끝 부분의 조건 참조). 내 기대가 잘못 되었습니까? 왜? 아니면 Visual Studio 2012 라이브러리 문제입니까?std :: codecvt_utf8 패싯의 문제

#include <locale> 
#include <codecvt> 
#include <cstdlib> 

int main() 
{ 
    std::mbstate_t state = std::mbstate_t(); 
    std::locale loc (std::locale(), new std::codecvt_utf8<wchar_t>); 
    typedef std::codecvt<wchar_t, char, std::mbstate_t> codecvt_type; 
    codecvt_type const & cvt = std::use_facet<codecvt_type> (loc); 

    wchar_t ch = L'\u5FC3'; 
    wchar_t const * from_first = &ch; 
    wchar_t const * from_mid = &ch; 
    wchar_t const * from_end = from_first + 1; 

    char out_buf[1]; 
    char * out_first = out_buf; 
    char * out_mid = out_buf; 
    char * out_end = out_buf + 1; 

    std::codecvt_base::result cvt_res 
     = cvt.out (state, from_first, from_end, from_mid, 
      out_first, out_end, out_mid); 

    // This is what I expect: 
    if (cvt_res == std::codecvt_base::partial 
     && out_mid == out_end 
     && state != 0) 
     ; 
    else 
     abort(); 
} 

여기서 기대 한번에 UTF-8 변환하지만 상기 조건부 if 중간의 out() 기능 출력 한 바이트 비주얼 스튜디오와 거짓이다 2012

UPDATE

무엇이 실패하면 out_mid == out_endstate != 0 조건입니다. 기본적으로, 적어도 하나의 바이트가 생성되고, UTF-8 시퀀스의 다음 바이트가 생성 가능해야하는 상태가 state 변수에 저장 될 것으로 기대합니다.

답변

4

codecvt::do_outpartial 리턴 코드의 표준 설명을 정확히 말한다 :

표 83에서

617,451,515,

partial 모든 소스 문자는 22.4.1.4.2 [locale.codecvt에서

변환.virtuals에]/5

결과 : 열거 값은 표 83에 partial 반환 값을 요약 된 바와 같이, (from_next==from_end) 경우, 대상 시퀀스 중 모든 가능한 대상 요소에 흡수되지 않았 음을 나타낸다 또는 다른 목적지 요소가 생성되기 전에 추가적인 소스 요소가 필요하다는 것을 의미한다. 귀하의 경우에는

모든 (영) 소스 문자가 기술적으로 출력 시퀀스의 내용을 아무것도합니다 (문장의 절은 입력하지 '가'),하지만, 일반적으로 말해서, "말한다없는, 전환되었다 없습니다 대상 시퀀스가 ​​사용 가능한 모든 대상 요소를 흡수하지 못했습니다 "여기 유효한 멀티 바이트 문자에 대해 설명합니다. 이들은 codecvt_utf8에 의해 생성 된 멀티 바이트 문자 시퀀스의 요소 인입니다.

더 명시 적으로 표준 표현이 좋을 것이지만, 여기에 두 가지 정황 증거의 조각입니다

하나 : 기존 C의 넓은 - 투 - 멀티 바이트 그 로케일 고유의 변형 보통 변환 기능 std::wcsrtombs (다음 바이트 문자 렌 총 바이트 한도를 초과 할 때

변환 정지 ...] 배열에 저장하는 다음과 같은 시스템이 제공 로켈 codecvt::do_out)의 기존 구현 호출 정의된다 dst에 의해 지적했다.

그리고 두 codecvt_utf8 기존의 구현을 보면 : 이미 마이크로 소프트의 탐구, 여기 ++의 libc에있어 무엇했습니다 여기 codecvt_utf8::do_out Windows에서 ucs2_to_utf8 및 기타 시스템에 ucs4_to_utf8 및 ucs2_to_utf8를 호출 does the following (주석 광산) :

 else if (wc < 0x0800) 
     { 
      // not relevant 
     } 
     else // if (wc <= 0xFFFF) 
     { 
      if (to_end-to_nxt < 3) 
       return codecvt_base::partial; // <- look here 
      *to_nxt++ = static_cast<uint8_t>(0xE0 | (wc >> 12)); 
      *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc & 0x0FC0) >> 6)); 
      *to_nxt++ = static_cast<uint8_t>(0x80 | (wc & 0x003F)); 
     } 

하나의 입력 와이드 문자를 사용하여 발생하는 멀티 바이트 문자에 맞지 않으면 출력 순서에 아무 것도 기록되지 않습니다.

+0

내가 기대하는 부분에 대해 당신이 논쟁하고있는 부분이 확실하지 않습니다. 분명히 해줄 수 있니? – wilx

+0

@wilx 함수는 멀티 바이트 문자가 아닌 바이트를 생성 할 것으로 기대합니다. 그렇게 할 수 없도록 지정된 적이 없으며 기존의 구현뿐만 아니라 비슷한 기능이 명시되어 있습니다. – Cubbi

+0

당신이 옳다고 가정하면 버퍼가 얼마나 커야하나요? 'std :: codecvt :: max_length()'? – wilx

2

비록 직접적인 언급은 없지만, 가장 논리적 인 행동은 std::codecvt::out이라고 생각합니다. 시나리오 다음을 고려 : 당신이했던 것처럼

  • 당신은 같은 방식으로 std::codecvt::out를 사용 - 모든 문자를 번역하지 귀하의 out_buf에 (아마도 모르고).
  • 당신은 지금, 당신은 당신이 당신의 문자열 직후 점을 알고로 buf_mid을 사용하기로 결정 이렇게하려면
  • 내부에 이미 내용을 추가하도록 당신의 out_buf (다시 std::codecvt::out 사용)에 다른 문자열을 번역 할 첫 번째 단계에서 번역 한 단어입니다.
  • 이제 std::codecvt::out는 (첫번째 후 문자를 가리키는 buf_mid) 여러분의 기대에 따라 일 경우 다음의 첫 번째 문자 당신의 out_buf/당신이 원하는 것이 정확히 무엇을 할이 경우에는 기대하지 않을 것이다 어떤 기록되지 않을 것입니다. 본질적으로

, extern_type*& to_next (std::codecvt::out의 마지막 매개 변수)는 왼쪽 곳의 기준으로 여기 당신을 위해입니다 - 그래서 당신은 계속 어디 있는지 - 당신이 시작했던 곳과 같은 위치가 (실제로 귀하의 경우 인 extern_type* to) 매개 변수.

+0

변환 상태에 관한 정보를 구현에 제공해야하는 'state' 변수/매개 변수도 있습니다. 위에서 설명한 내용은 IMHO에서 상태를 처리하고 ['codecvt :: unshift()'] (http://en.cppreference.com/w/cpp/locale/codecvt/unshift)를 호출해야합니다. 출력 버퍼가 단지 1 바이트 길이라면) 다시 추가 문자열에'codecvt :: out()'을 다시 호출하기 전에. – wilx

+0

@wilx 그게 아주 좋은 지적이야. Microsoft는 귀하의 질문에 아직 회신 했습니까? (나는 그들의 사이트에서 귀하의 질문을 보았습니다.) –

+0

아직 두 개의 자동화 된 메시지 옆에 어떤 반응도 없었습니다. – wilx

관련 문제