vswprintf не работает для определенных кодовых точек Unicode в Mac OS X

Я получаю необъяснимые сбои (возвращаемое значение -1) от vswprintf при использовании GCC и Mac OS X (проверено с gcc 4.0 и 4.2.1 в Mac OS X 10.6 и 10.8. GCC под Linux не влияет. Visual Studio также не затрагивается).

Чтобы продемонстрировать проблему, я минимально адаптировал пример из здесь, чтобы он распечатывал vswprintf возвращаемое значение:

/* vswprintf example */
#include <stdio.h>
#include <stdarg.h>
#include <wchar.h>

void PrintWide ( const wchar_t * format, ... )
{
    wchar_t buffer[256];
    va_list args;
    va_start ( args, format );
    int res = vswprintf ( buffer, 256, format, args );
    wprintf ( L"result=%d\n", res );
    fputws ( buffer, stdout );
    va_end ( args );
}

int main ()
{
    wchar_t str[] = L"test string has %d wide characters.\n";
    PrintWide ( str, wcslen(str) );
    return 0;
}

Из моих тестов видно, что, в зависимости от значения str, vswprintf иногда дает сбой. Примеры:

wchar_t str[] = L"test string has %d wide characters.\n"; // works
wchar_t str[] = L"ßß® test string has %d wide characters.\n"; // works
wchar_t str[] = L"日本語 test string has %d wide characters.\n"; // FAILS
wchar_t str[] = L"Π test string has %d wide characters.\n"; // FAILS
wchar_t str[] = L"\u03A0 test string has %d wide characters.\n"; // FAILS

Похоже, что любые строки, содержащие символы с кодовыми точками Unicode выше 0xff, вызовут эту проблему. Может ли кто-нибудь пролить свет на то, почему это происходит? Кажется, это слишком большая проблема, чтобы не замечать ее раньше!


person Xaxx    schedule 15.03.2013    source источник
comment
Соответствует ли кодировка вашего исходного файла кодировке, ожидаемой в строках?   -  person Dmitri    schedule 15.03.2013
comment
Я ожидаю, что вызов fputws потерпит неудачу в локали "C" по умолчанию для символов, выходящих за пределы допустимого диапазона, но vswprintf должен работать.   -  person Chris Dodd    schedule 16.03.2013
comment
Как следует из названия, GCC vswprintf не существует. Причина, по которой GCC в GNU/Linux ведет себя иначе, чем GCC в Mac OS X, заключается в том, что vswprintf не имеет ничего общего с GCC, он предоставляется библиотекой C ОС, libc   -  person Jonathan Wakely    schedule 17.03.2013
comment
Спасибо. Я изменил заголовок соответственно.   -  person Xaxx    schedule 21.03.2013


Ответы (1)


Если вы установите локаль, все должно быть в порядке. Чтобы подобрать переменную среды, вы можете сделать это:

setlocale(LC_CTYPE, "");   // include <locale.h>

или установить его явно. Это связано с тем, что все функции вывода должны знать, какую кодировку использовать.

OS X вообще не может выполнить vswprintf, в то время как Linux запускает его (хотя символы будут неправильными при печати).

Вот соответствующий раздел из документации glibc:

   If  the  format  string contains non-ASCII wide characters, the program
   will only work correctly if the LC_CTYPE category of the current locale
   at  run time is the same as the LC_CTYPE category of the current locale
   at compile time.  This is because the wchar_t representation  is  plat‐
   form-  and  locale-dependent.   (The  glibc  represents wide characters
   using their Unicode (ISO-10646) code point, but other  platforms  don't
   do  this.
person teppic    schedule 15.03.2013
comment
На самом деле, IMO вызов vswprintf не должен зависеть от локали, но вызов fputsw должен завершиться ошибкой... - person Chris Dodd; 16.03.2013
comment
Вы действительно правы! Между прочим, в Ubuntu 11.04 вызов не только завершается успешно, но и выводится правильно даже без установки локали. - person Xaxx; 21.03.2013
comment
@Xaxx - рад, что это помогло. Я думаю, что Ubuntu 11.04 должна быть более либеральной. Я попробовал в Ubuntu 12.10, и он дал неправильные символы (страница руководства говорит, что LC_CTYPE должен быть установлен). - person teppic; 21.03.2013
comment
@teppic - я должен был быть более точным. В Ubuntu вызов vswprintf завершается успешно, и буфер результатов заполняется правильными кодовыми точками. Однако, если вы затем попытаетесь распечатать его (например, с помощью printf), вывод будет неправильным, если не установлен LC_CTYPE. - person Xaxx; 21.03.2013
comment
@Xaxx - а, понятно. Я не проверял это в 12.10. Но да, в OS X вызов вообще не работает, даже с ASCII. - person teppic; 21.03.2013