Подробности

[В начало]

Проблема в реализации № S0675

Краткое описание

codecvt::do_in/do_out возвращают "ok", когда выходная последовательность имеет нулевую длину

Подробное описание

Функции-члены класса codecvt<wchar_t, char, mbstate_t>

result in(stateT& state, const externT* from, const externT* from_end, const externT*& from_next, internT* to, internT* to_limit, internT*& to_next) const

и

result out(stateT& state, const internT* from, const internT* from_end, const internT*& from_next, externT* to, externT* to_limit, externT*& to_next) const

возвращают "ok" в случае, когда (to==to_limit), но (from < from_end), иными словами, когда выходная последовательность не вмещает ни одного элемента, а входная непустая.

Тем не менее, из описания возвращаемого значения этих функций (ISO/IEC 14882, раздел 22.2.1.5.2.4) следует, что должен возвращаться "partial":

ok - completed the conversion
partial - not all source characters converted
error - encountered a character in [from,from_end) that it could not convert
noconv - internT and externT are the same type, and input sequence is identical to converted sequence

Эти функции в действительности возвращают "partial", когда выходная последовательность непуста, но не может вместить все преобразованные символы из входной последовательности:
0< (to_limit - to) < (from_end - from).

Приведённый ниже пример демонстрирует данную проблему.

Раздел стандарта

Linux Standard Base C++ Specification 3.2, Chapter 9. Libraries, 9.1. Interfaces for libstdcxx, который ссылается на ISO/IEC 14882: 2003 Programming languages --C++, section 18.6.4

Пример

#include <locale>
using namespace std;

/*
 * Derives from codecvt<> class for make destructor
 * and target functions public (instead of protected).
 */
class codecvt_my : public codecvt<wchar_t, char, mbstate_t>
{
public:
    using codecvt<wchar_t, char, mbstate_t>::do_in;
    using codecvt<wchar_t, char, mbstate_t>::do_out;
    
    virtual ~codecvt_my(){};
};
/*
 * Converts integral value of codecvt_base::result
 * to string representation.
 */
const char* result_to_str(codecvt_base::result result)
{
    switch(result)
    {
    case codecvt_base::ok:
        return "ok";
    case codecvt_base::error:
        return "error";
    case codecvt_base::noconv:
        return "noconv";
    case codecvt_base::partial:
        return "partial";
    default:
        return "(unknown result)";
    }
}
/*
 * Test for do_out() function
 * with different sizes of input and ouput sequences.
 */
template<size_t input_size, size_t output_size>
void test_out()
{
    wchar_t from[input_size];
    for(wchar_t *tmp = from; tmp < from + input_size; tmp++)
        *tmp = L'a';
    const wchar_t *from_next;
    
    char to[output_size];
    char *to_next;
    
    codecvt_my obj;
    mbstate_t state = mbstate_t();

    printf("Calls do_out() function when size of input sequence "
           "is %zu, output - %zu:\n",
           input_size, output_size);

    codecvt_base::result result = obj.do_out(state,
        from, from + input_size, from_next,
        to, to + output_size, to_next);

    printf("do_out() returns %s.\n",
        result_to_str(result));
}
/*
 * Test for do_in() function
 * with different sizes of input and ouput sequences.
 */
template<size_t input_size, size_t output_size>
void test_in()
{
    char from[input_size];
    for(char *tmp = from; tmp < from + input_size; tmp++)
        *tmp = 'a';
    const char *from_next;
    
    wchar_t to[output_size];
    wchar_t *to_next;
    
    codecvt_my obj;
    mbstate_t state = mbstate_t();

    printf("Calls do_in() function when size of input sequence" 
           "is %zu, output - %zu:\n",
           input_size, output_size);

    codecvt_base::result result = obj.do_in(state,
        from, from + input_size, from_next,
        to, to + output_size, to_next);

    printf("do_in() returns %s.\n",
        result_to_str(result));
}
int main()
{
    test_out<2,1>();
    test_out<2,0>();
    test_in<2,1>();
    test_in<2,0>();
    return 0;
}

Компонент

libstdc++

Принято

GCC Bugzilla 37475

[В начало]