LINUX.ORG.RU

wchar_t

 


3

2

ЧЯДНТ?

$ echo $LANG
en_US.UTF-8

$ gcc --version
gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
$ cat src.c 
#include <stdio.h>
#include <wchar.h>
int main ()
{
   wchar_t word[] = L"Дробь";
   wprintf(L"%s\n", word);
   return 0;
}
$ gcc src.c
$
$./a.out
<тут-какойто-непонятный-символ>
★★★★★

#include <stdio.h>
#include <wchar.h>
#include <locale.h>
int main ()
{
   setlocale(LC_CTYPE, "ru_RU.UTF-8");
   wchar_t word[] = L"Дробь";
   wprintf(L"%ls\n", word);
   return 0;
}
happycorsair
()
Ответ на: комментарий от happycorsair

Не хотелось бы таких пререквизитов
Вот так работает:

#include <stdio.h>
int main ()
{
   char word[] = "Дробь";
   printf("%s\n", word);
   return 0;
}
Но беда с адресной арифметикой:
#include <stdio.h>
int main ()
{
   char word[] = "Дробь";
   printf("%s\n", word+1);
   return 0;
}

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

Во, вот так работает, и арифметика работает. А можно как-то разъяснить смысл сего шаманства и степень его необходимости?

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

     Only three locales are defined by default, the empty string «» which
     denotes the native environment, and the «C» and «POSIX» locales, which
     denote the C language environment.  A locale argument of NULL causes
     setlocale() to return the current locale.  By default, C programs start
     in the «C» locale.  The only function in the library that sets the locale
     is setlocale(); the locale is never changed as a side effect of some
     other routine.

DISCLAIMER: я не специалист в этой области, я просто умею хорошо находить информацию ☺

beastie ★★★★★
()
Последнее исправление: beastie (всего исправлений: 1)
Ответ на: комментарий от beastie

В общем слусае (без костылей) с utf-8 адрессная арифметика не работает.

Это понятно, но разве wchar_t сам по себе не костыль для этого?

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

Хм, странно, но наверное это действительно причина

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

Не за что, с удовольствием. Отмечай как решённую. ☺

beastie ★★★★★
()

ИМХО, чтобы правильно выводило, локаль должна быть UTF-16

Harald ★★★★★
()

ЧЯДНТ?

en_US.UTF-8

wprintf

либо крестик, либо трусы. Либо ставь локаль с широкими символами, либо используй простую printf, и простые char'ы.

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

В общем слусае (без костылей) с utf-8 адрессная арифметика не работает.

а как она должна работать, если все символы разного размера? Иные по 1 байту, иные по 2, а всякие ☣ по 3. Ясное дело, что прибавляя 1 char ты переходишь на середину символа, и получается ерунда.

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

Интересные факты: в UTF-8 арифметика вполне себе работает, но только на одну букву вперед/назад. wchar_t непереносим даже между компиляторами одной платформы. Обращение к пятой/десятой букве теряет смысл после википедия/уникод.

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

либо крестик, либо трусы. Либо ставь локаль с широкими символами, либо используй простую printf, и простые char'ы.

Не пиши бред. glibc сама умеет конвертировать wchar_t в нужную локаль.

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

дык _все_ функции *printf(3) конвертируют в юникод, если в ASCII не получается.

Wide characters from the array are converted to multibyte characters

Но это касается *printf(3), и как-то слабо относится к самим wchar_t. Это только запись в файл такая.

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

Что-то я не пойму о чём ты тут флудишь, всё уже вроде выяснили, всё нормально работает (wchar_t + setlocale = строка юникода с работающей адресной арифметикой)

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

Интересные факты: в UTF-8 арифметика вполне себе работает, но только на одну букву вперед/назад.

Всё нормально работает и не на одну букву:

#include <stdio.h>
#include <locale.h>
#include <wchar.h>

int main ()
{
	wchar_t word[] = L"Дробь";
	setlocale(LC_ALL, "");
	wprintf(L"%ls\n", word+2);
	return 0;
}

$ gcc src.c 
$ ./a.out 
обь
af5 ★★★★★
() автор топика
Ответ на: комментарий от af5

Всё нормально работает и не на одну букву:

а это и не UTF-8.

о чём ты тут флудишь, всё уже вроде выяснили, всё нормально работает

видать не все ещё выяснили.

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

а это и не UTF-8

Чё правда?

#include <stdio.h>
#include <locale.h>
#include <wchar.h>

int main ()
{
	wchar_t word[] = L"Дробь";
	setlocale(LC_ALL, "");
	wprintf(L"%X\n", word[0]);
	return 0;
}
$ gcc src.c 
$ ./a.out 
414

код удивительным образом совпадает с utf-8 буквой 'Д'
http://www.utf8-chartable.de/unicode-utf8-table.pl

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

Чё правда?

да. Двойку ты прибавлял к wchar_t, а вовсе не к UTF-8.

код удивительным образом совпадает с utf-8 буквой 'Д'

что в этом удивительного, если у нас wchar_t реализован как UTF-32? Вот только буква Д в utf-8 занимает 2 байта, а у тебя — 4. А вот ☣ занимает 3 байта.

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

Но это касается *printf(3), и как-то слабо относится к самим wchar_t. Это только запись в файл такая.

Кроме чтения/записи файлов можно ещё конвертировать wide char <-> multibite просто в памяти. Этого недостаточно?

Deleted
()
Ответ на: комментарий от drBatty

да. Двойку ты прибавлял к wchar_t, а вовсе не к UTF-8.

спасибо, кэп

что в этом удивительного, если у нас wchar_t реализован как UTF-32? Вот только буква Д в utf-8 занимает 2 байта, а у тебя — 4. А вот ☣ занимает 3 байта.

продолжаю непонимать суть твоей проблемы. Радуйся, ☣ влезет в 4 байта и будет правильно работать ☣☣☣☣☣☣☣☣+2

#include <stdio.h>
#include <locale.h>
#include <wchar.h>

int main ()
{
	wchar_t word[] = L"☣☣☣☣☣☣☣☣";
	setlocale(LC_ALL, "");
	wprintf(L"%ls\n", word+2);
	return 0;
}
./a.out
☣☣☣☣☣☣

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

Радуйся, ☣ влезет в 4 байта и будет правильно работать ☣☣☣☣☣☣☣☣+2

будет конечно. Вот только к utf-8 это никак не относится. Ибо ☣ занимает 3 байта, а прибавляется 8 байт (2 символа).

Интересные факты: в UTF-8 арифметика вполне себе работает, но только на одну букву вперед/назад.

Всё нормально работает и не на одну букву:

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

у меня нет проблем. В UTF-8 арифметика вообще не работает, кроме случая ASCII. А у вас она, судя по цитатам, как-то работает.

В частности у тебя она работает в UTF-32. А у анонимуса я не понял как(он код не предоставил).

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

Интересные факты: в UTF-8 арифметика вполне себе работает, но только на одну букву вперед/назад.

Всё нормально работает и не на одну букву:

эти непонятны.

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

Тогда смысл вообще во всех этих wchar_t если все равно арифметика не гарантирована? Кажется она только для utf32 может быть как-то гарантироваться, в остальных случаях это же просто везение. Тогда уж лучше юзать char * а для операций с символами уже тащить что-нибудь в стиле icu.

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

Ты ведь сам понял, что по сути wchar_t == UTF-32, setlocale с помощью glibc сконвертировал мою utf-8 в utf-32 (или что-то похожее) и теперь строка представляет собой полноценный массив 4-байтных чаров, на котором арифметика не может не работать

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

Ты ведь сам понял, что по сути wchar_t == UTF-32

это НЕ так. Это только в нашей текущей реализации так. А как оно будет — хз. В венде недавно было 16 бит, ЕМНИП. Да и похоже сейчас 16.

setlocale с помощью glibc сконвертировал мою utf-8 в utf-32

это скорее gcc сконвертировал текст из исходника в UTF-32.

и теперь строка представляет собой полноценный массив 4-байтных чаров, на котором арифметика не может не работать

арифметика-то работает, но вот совершенно непонятно, что с этой строкой делать. Как например имя файла задать? Долбаться с wctomb(3)? Да нафига мне оно надо?

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

а вот если бы у нас использовался С++, то можно было бы переопределить операторы ++, +, += и прибавлять 1,2 или 3 байта в зависимости от количества единичных старших битов операнда :)

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

Да там 16 бит, я в линуксах whar_t никогда не юзал, предпочитая char и честно был уверен, что там также.

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

wchar_t это не UTF-8 (и не уникод, да). Настоятельно рекомендую прочитать хотя бы статейку на википедии.

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

например имя файла задать?

как-то так например:

#include <stdio.h>
#include <locale.h>
#include <wchar.h>

int main ()
{
	wchar_t word[] = L"Дробь";
	setlocale(LC_ALL, "");
	char str[256];
	wcstombs(str, word);
	FILE *fp = fopen(str,"w");
	fwprintf(fp, L"%ls\n", word+2);
	fclose(fp);
	return 0;
}
$ ls
a.out src.c

$ gcc src.c
$ ./a.out
$ ls
a.out src.c  Дробь

$ cat Дробь 
обь

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

Ну емае, прочитай уже, а? И покажи код, который гарантированно выдерет букву «й» из слова «плохой» в UTF-8/16/32, а мы еще посмеемся.

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

wchar_t это не UTF-8 (и не уникод, да). Настоятельно рекомендую прочитать хотя бы статейку на википедии.

ути-пути :)

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

Давай я расскажу тебе, ок. wchar_t это исторический тип, когда пошла свистопляска с начальной поддержкой уникода. На некоторых платформах (вин32, ява упс) он 16-битный и не покрывает все символы. UTF-N это способ кодирования кодэпоинтов N-битными словами. Все кодэпоинты *на данный момент* влезают в 20 бит или около того, точно забыл. То, что wchar_t большей частью совпадает с UTF-16/32, не должно вводить в заблуждение. Ну и самое главное: в уникодированном слове «плохой» может быть 6 кодэпоинтов, а может быть 7, опа. Дальше лениво, man NFC NFD. Каждый, кто пытается использовать смещения в уникодных строках обречен на нормализацию (дорого) или провал (фейл). Юзайте поточную обработку и UTF-8 как универсальное представление. /thread

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

Вот весь твой пост:

можно ещё конвертировать wide char <-> multibite просто в памяти.

дык как?

Что не так?

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