LINUX.ORG.RU

[GCC][MinGW] Кроссплатформенность и wchar_t

 ,


1

0

Здраствуйте! Существует проблема. Нужно сделать так чтобы код скомпиленный под разными компиляторами (GCC и MinGW) работал одинаково. Это возможно? PS: Буду оч признателен за советы

Есть код:

// uni.c
#include <stdio.h>
#include <wchar.h>
#include <locale.h>

int main(void)
{
	setlocale(LC_ALL, "ru_RU.UTF-8");
	printf("Size of wchar_t = %d\n", sizeof(wchar_t));
	FILE* f = fopen("/home/maxim/uni.txt", "r");
	if (!f)
		return;
	printf("Read = 0x%04X\n", fgetwc(f));
	printf("Read = 0x%04X\n", fgetwc(f));
	return 0;
}

Есть файл uni.txt записанный в кодировке UTF-8:

$ cat uni.txt
Яблоко

Если скомпилировать программу под gcc и выполнить то получим:

$ gcc -o uni uni.c && ./uniSize of wchar_t = 4
Read = 0x042F
Read = 0x0431

Если скомпилировать программу под mingw и выполнить то получим:

$ i486-mingw32-gcc -o uni.exe uni.c && wine ./uni.exe
Size of wchar_t = 2
Read = 0xFFD0
Read = 0xFFAF

Если запустить нативно программу под виндой то там будет такое:

>uni.exe
Size of wchar_t = 2
Read = 0x00D0
Read = 0x00AF

setlocale это очень плохо, а wchar_t - не кроссплатформенный тип. Для кодировок есть libiconv.
а utf-8 это char*

Love5an
()

(Ой матьмать, чтойто с ответной формой!?)

wchar_t - компиляторозависим, и никак не utf8.

utf8 - кодировка с переменным размером символа (некоторые символы занимают байт, некоторые - два, а в военное время даже 4). Поэтому символ в ней неможет быть описан "простым" встроенным типом (у них размер постоянен).

Для работы с utf8 нужны специальные либы.

Иногда он применяется для кродировок unicode-16 или unicode-32, но это тоже несовсем правильно (в 16битном юникоде есть спецсимволы большей длины) и платформозависимо. Вобщем, wchar_t не нужен =)

ierton ★★
()

wchar_t тут непричем. Проверь, что возвращает setlocale. Скорее всего это нулевой указатель (установить локаль не получилось).

mannaz
()
Ответ на: комментарий от Legioner

Сделать по идее можно, и он вполне кроссплатформенный, только проще таки заюзать специальные либы. Слишком уж намудрено с этим юникодом в стандартной библиотеке, простую вещь сделали сложной.

Legioner ★★★★★
()
Ответ на: комментарий от Legioner

Расскажите плиз какие существуют либы. Вообщем у меня тут почти готовый компилятор есть который я написал сам (дипломная работа), по логике этот компилятор должен читать файлы в UTF-8, причём на любой платформе. Компилятор пошаговый, однопроходный. Файл считывается по-символьно при помощи fgetwc(f_in). Вот нужна значит такая либа которая могла заменить эту функцию (ну и не только, но эта самая важная)

anterior
() автор топика

> setlocale(LC_ALL, "ru_RU.UTF-8");

названия локалей — платформенно зависимы. в винде локаль с кодировкой utf-8 называется по другом, что-то типа Russian_Russian.65001

Eshkin_kot ★★
()

setlocale(LC_ALL, NULL); выставит системную локаль.

legolegs ★★★★★
()
Ответ на: комментарий от Eshkin_kot

>Russian_Russian.65001
Ага, нашёл. Установил. Возвращает не пустую строку. Но толку от этой команды никакого. Поведение одинаковое что и без неё

anterior
() автор топика
Ответ на: комментарий от anterior

>Расскажите плиз какие существуют либы.

Glib например с utf-8 вполне работает. Вот только не особо красиво это для компилятора.

Вообще вам туда:

http://www.cl.cam.ac.uk/~mgk25/unicode.html

anonymous
()
Ответ на: комментарий от bvvv

Да, уже разбираюсь:) Тяжёлая либа, но есть функции для работы с I/O

anterior
() автор топика
Ответ на: комментарий от anterior

Конечно дело не моё, но по логике компилятор должен читать в кодировке текущей локали. Установил я локаль в ru_RU.KOI8-R - он должен предполагать, что файлы в KOI8-R, а не в UTF-8. И в этом случае в программе вообще не надо указывать конкретную локаль, достаточно setlocale(LC_ALL, ""); По крайней мере так делают все компиляторы, которые я видел.

Legioner ★★★★★
()
Ответ на: комментарий от Legioner

>но по логике компилятор должен читать в кодировке текущей локали.

Так делают mp3-плееры с тэгами. Радости - ноль.

legolegs ★★★★★
()
Ответ на: комментарий от Legioner

Дело в том что это необычный компилятор, тут должна быть другая логика=)

Всем спасибо за ответы!

anterior
() автор топика
Ответ на: комментарий от legolegs

Текстовые файлы и теги - немного разные вещи. В тегах должна быть указана кодировка, в текстовых файлах кодировка указываться не может.

Legioner ★★★★★
()
Ответ на: комментарий от Legioner

>В тегах должна быть указана кодировка

Нет. В тегах кодировка должна быть стандартной, одинаковой для всех.

legolegs ★★★★★
()

> libicu
Помоему эту супер мега либу скомпилить под MinGW не реально. Я как только не извращался, но так и не осилил.. В доках предлагается попробовать компилить либо при помощи MSVC++, либо Cygwin/GCC. Погуглив тоже не смог найти никакой информации. Ну и нафиг её.

А вот если попробовать пример вот такой:
#include <stdio.h>
int main(void)
{
printf("%X\n", L'Я');
return 0;
}
скомпилить и запустить:
$ gcc -o uni uni.c && ./uni
42F
$ i486-mingw32-gcc -o uni.exe uni.c && wine ./uni.exe
42F

То получим одинаковый результат. Таким образом можно написать свой вариант функции fgetwc() который мог бы считывать UTF-8 символ из файла, затем используя правила преобразования, преобразовывал его в UTF-16/32. А далее можно работать с преобразованным символом используя стандартные функции языка Си=) Думаю этого функционала мне бы хватило, и тогда не надо никаких мега либ)

anterior
() автор топика
Ответ на: комментарий от legolegs

Если это заложено в формате, это означает то же самое, что я сказал.

Legioner ★★★★★
()
Ответ на: комментарий от Love5an

> там же прекомпиленные бинарники есть, на сайте их
Ну да, видел:) Только вот они не хотят под mingw работать. Кинул я их значит в /usr/i486-mingw32, а потом натравил i486-mingw32-gcc на тестовый исходник, после чего i486-mingw32-gcc засегфолтился при попытке компоновки. Я думаю тут дело в том что прекомпиленные бинарники были собраны с помощью MSVC++ и используют msvcrt.dll. А надо ведь mingw.dll получается...

anterior
() автор топика
Ответ на: комментарий от anterior

а это c++ библиотека?
если да, то да, несовместимы
если чистая сишка, проблем быть не должно

Love5an
()

Проблему решить не поможет, но для справки:
1. Мусор во втором Read = 0xFFD0
>> printf("Read = 0x%04X\n", fgetwc(f));
<< printf("Read = 0x%04X\n", (int)fgetwc(f));
2. в третьем нативно под виндой fgetwc объявлен
wint_t fgetwc(FILE*); /*wchar_t отдыхает*/

anonymous
()
Ответ на: комментарий от anterior

> Ага, нашёл. Установил. Возвращает не пустую строку. Но толку от этой команды никакого. Поведение одинаковое что и без неё

а какая у Вас версия mingw ? стандартная на базе gcc 3 ? если есть возможность, попробуйте новые, на базе gcc 4, например http://www.tdragon.net/recentgcc/

Eshkin_kot ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.