Распечатать строку UTF-32 с помощью wprintf - PullRequest
0 голосов
/ 19 июня 2020

Я переношу код с использования wchar_t на char32_t, и при компиляции с установленным флагом -Werror=pointer-sign возникает следующая проблема:

// main.c

#include <uchar.h>
#include <wchar.h>

int main(void) {
    wprintf(U"some data\n");
}

Компиляция: gcc -std=c11 -Werror=pointer-sign main.c

Вывод:

main.c: In function ‘main’:
main.c:5:10: error: pointer targets in passing argument 1 of ‘wprintf’ differ in signedness [-Werror=pointer-sign]
  wprintf(U"some data\n");
          ^~~~~~~~~~~~~~
In file included from main.c:2:
/usr/include/wchar.h:587:12: note: expected ‘const wchar_t * restrict’ {aka ‘const int * restrict’} but argument is of type ‘unsigned int *’
 extern int wprintf (const wchar_t *__restrict __format, ...)
            ^~~~~~~

Чтобы исправить это, я могу сделать:

wprintf((const int *)U"some data\n");

//or
printf("%ls\n", U"some data");

Хотя это довольно неприятно. Есть ли простой и приятный способ сделать это? В чем реальная разница между const unsigned int* и const signed int*, помимо типа данных, на который он указывает? Возможно ли это опасно, или я должен вообще отключить флаг?

1 Ответ

0 голосов
/ 19 июня 2020

char32_t - это тип без знака .

wchar_t - это либо знак , либо без знака , в зависимости от реализации. В вашем случае это подписанный .

Вы не можете передать указатель на беззнаковый, где ожидается указатель на подписанный. Итак, да, вам нужно приведение типов, однако вы должны выполнять приведение к const wchar_t *, поскольку это то, что на самом деле ожидает wprintf() (wchar_t просто оказывается реализовано как int на ваш компилятор, но не приводите к нему напрямую):

wprintf((const wchar_t *)U"some data\n");

Он не станет намного чище, если вы не заключите его в свою собственную функцию, например:

int wprintf32(const char32_t *str, ...)
{
    va_list args;
    va_start(args, str);
    int result = vwprintf((const wchar_t *)str, args);
    va_end(args);
    return result;
}

wprintf32(U"some data\n");

Обратите внимание, что этот код не будет работать должным образом вообще на платформах, где sizeof(wchar_t) < sizeof(char32_t), например Windows. На этих платформах, где sizeof(wchar_t) равно 2, вам нужно будет фактически преобразовать ваши строковые данные из UTF-32 в UTF-16, например:

int wprintf32(const char32_t *str, ...)
{
    va_list args;
    int result;

    va_start(args, str);

    if (sizeof(wchar_t) < sizeof(char32_t))
    {
        wchar_t *str = convert_to_utf16(str); // <-- for you to implement
        result = vwprintf(str, args);
        free(str);
    }
    else
        result = vwprintf((const wchar_t *)str, args);

    va_end(args);
    return result;
}

wprintf32(U"some data\n");
...