Проблемы с std::cout в Linux
Модератор: Модераторы разделов
-
shau-kote
- Сообщения: 417
- Статус: злобный хоббит
- ОС: Arch
Проблемы с std::cout в Linux
Всем доброго времени суток.
Являясь студентом, постоянно пишу на C++. До этого использовал MinGW под Windows, но недавно решил вернуться на Arch, в связи с чем логично стал использовать gcc.
Раньше для вывода я просто использовал std::wcout, вызывая при этом setlocale(LC_ALL, "Russian") в начале программы и предваряя все строковые литералы буквой "L".
Всё прекрасно работало, как вывод русского текста, так и вывод чего-либо ещё.
Но сейчас, на Linux'е, я столкнулся с двумя проблемами:
1) Русский текст выводится вопросительными знаками. При том, что в системе установлена локаль ru_RU.UTF-8 и консоль поддерживает вывод русских букв;
2) По окончанию программы выводится какой-то мусор, выглядящий как символ % на сером фоне. Лечится с помощью cout << endl, но всё равно непонятно, откуда он берётся.
Подскажите, пожалуйста, как решить первую проблему и в чём причина второй?
Являясь студентом, постоянно пишу на C++. До этого использовал MinGW под Windows, но недавно решил вернуться на Arch, в связи с чем логично стал использовать gcc.
Раньше для вывода я просто использовал std::wcout, вызывая при этом setlocale(LC_ALL, "Russian") в начале программы и предваряя все строковые литералы буквой "L".
Всё прекрасно работало, как вывод русского текста, так и вывод чего-либо ещё.
Но сейчас, на Linux'е, я столкнулся с двумя проблемами:
1) Русский текст выводится вопросительными знаками. При том, что в системе установлена локаль ru_RU.UTF-8 и консоль поддерживает вывод русских букв;
2) По окончанию программы выводится какой-то мусор, выглядящий как символ % на сером фоне. Лечится с помощью cout << endl, но всё равно непонятно, откуда он берётся.
Подскажите, пожалуйста, как решить первую проблему и в чём причина второй?
-
Bizdelnick
- Модератор
- Сообщения: 21507
- Статус: nulla salus bello
- ОС: Debian GNU/Linux
Re: Проблемы с std::cout в Linux
Что за текст? Он, часом, не достался в наследство от винды и не пребывает в какой-нибудь cp1251?
Аналогично - не остался ли там в наследство от винды какой-нибудь '\r'?
Пишите правильно:
| в консоли вку́пе (с чем-либо) в общем вообще | в течение (часа) новичок нюанс по умолчанию | приемлемо проблема пробовать трафик |
-
shau-kote
- Сообщения: 417
- Статус: злобный хоббит
- ОС: Arch
Re: Проблемы с std::cout в Linux
Никак нет.
Вывожу строковый литерал либо строку считанную со входного потока.
Строковый литерал впечатан в исходный код, который набран в текстовом редакторе в самом Arch'е в UTF-8.
Вывожу строковый литерал либо строку считанную со входного потока.
Строковый литерал впечатан в исходный код, который набран в текстовом редакторе в самом Arch'е в UTF-8.
-
Женя Подсыпальников
- Сообщения: 482
Re: Проблемы с std::cout в Linux
// Arch, ru_RU.UTF-8, edited in nano, pocessed in xfce4-terminal :
$ c++ first.cpp -o first.exe
$ ./first.exe
Программирование
$

Код: Выделить всё
// first.cpp
#include <iostream>
int main()
{
std::cout << "Программирование\n";
return 0;
}$ c++ first.cpp -o first.exe
$ ./first.exe
Программирование
$
Пойдём на рыбалку !
-
shau-kote
- Сообщения: 417
- Статус: злобный хоббит
- ОС: Arch
Re: Проблемы с std::cout в Linux
Опа, действительно.
Я писал std::wcout << L"кириллица", а не как Вы. Написал как у Вас - действительно, работает.
Любопытно, Вы не объясните, почему?
Ведь текст всё же в UTF-8, стало быть выводить его нужно в соответствующий поток, нет?
Вообще, это несколько неожиданно для меня, попробовал сейчас следующее:
- работает!
Но разве обычный char пригоден для хранения символов в UTF-8?..
Я писал std::wcout << L"кириллица", а не как Вы. Написал как у Вас - действительно, работает.
Любопытно, Вы не объясните, почему?
Ведь текст всё же в UTF-8, стало быть выводить его нужно в соответствующий поток, нет?
Вообще, это несколько неожиданно для меня, попробовал сейчас следующее:
Код: Выделить всё
#include <iostream>
int main()
{
char str[100];
std::cin >> str;
std::cout >> str;
return 0;
}- работает!
Но разве обычный char пригоден для хранения символов в UTF-8?..
-
shau-kote
- Сообщения: 417
- Статус: злобный хоббит
- ОС: Arch
Re: Проблемы с std::cout в Linux
UPD
С "мусором" разобрался, выведя cat'ом исходный текст программы и заметив в конце вывода то же самое. Сменил zsh на дефолтный bash - исчезло.
Очевидно, какая-то ерунда с конфигурацией zsh. :\
С "мусором" разобрался, выведя cat'ом исходный текст программы и заметив в конце вывода то же самое. Сменил zsh на дефолтный bash - исчезло.
Очевидно, какая-то ерунда с конфигурацией zsh. :\
-
/dev/random
- Администратор
- Сообщения: 5480
- ОС: Gentoo
Re: Проблемы с std::cout в Linux
Указывать следует либо корректную локаль (например, "ru_RU.UTF8"), либо пустую строку для автоопределения. Несуществующие локали, вроде вашей, формально приводят к неопределённому поведению, на практике работают как синоним "C".
Правильный код (только ключевые строки):
Код: Выделить всё
setlocale(LC_ALL, "");
std::wcout << L"Привет, мир!\n";Символов - нет. Байтов - да. Если так делать, то один символ может занять больше одного байта. И кстати, не путайте UTF-8 и Unicode.
Строки вида L"" хранят данные в каком-либо внутреннем представлении юникода, обычно UCS2 или UCS4, а wcout перекодирует текст в установленную локалью кодировку (возможно, UTF-8, а возможно, что-то однобайтовое).
Строки вида "" хранят набор байтов (NUL-terminated), в той кодировке, в которой они были введены в исходниках. cout выводит их без перекодирования и не оглядываясь на локаль. Если кодировка исходников и кодировка терминала совпадают, вывод будет правильным. Иначе - нет.
zsh так уведомляет пользователя, что запущенная программа вывела незавершённую строку (без "\n" в конце). Для удобства.
-
NickLion
- Сообщения: 3408
- Статус: аватар-невидимка
- ОС: openSUSE Tumbleweed x86_64
Re: Проблемы с std::cout в Linux
Поправлю, что L"" и std::wcout работают с wide-char — wchar_t — для windows это обычно 2 байта и UCS2 (до Win2000 включительно) или UTF-16 (WinXP+), для Linux — 4 байта и UTF-32.
-
shau-kote
- Сообщения: 417
- Статус: злобный хоббит
- ОС: Arch
Re: Проблемы с std::cout в Linux
/dev/random, спасибо за подробный комментарий.
В смысле, в Linux? Или вообще?
Поскольку, когда я компилировал свой код в Windows, я поначалу тоже полагал, что нужно передать что-то вроде "utf-8", а оказалось, что рабочим является именно тот вариант, что я привёл.
И я правильно, понял, что вариант, приведённый Женей, хоть и является рабочим, но, вообще говоря, не является "хорошим", поскольку слабо переносим, да и вообще не гарантирует корректного вывода?
/dev/random писал(а): ↑14.03.2013 09:07Указывать следует либо корректную локаль (например, "ru_RU.UTF8"), либо пустую строку для автоопределения.
В смысле, в Linux? Или вообще?
Поскольку, когда я компилировал свой код в Windows, я поначалу тоже полагал, что нужно передать что-то вроде "utf-8", а оказалось, что рабочим является именно тот вариант, что я привёл.
И я правильно, понял, что вариант, приведённый Женей, хоть и является рабочим, но, вообще говоря, не является "хорошим", поскольку слабо переносим, да и вообще не гарантирует корректного вывода?
-
/dev/random
- Администратор
- Сообщения: 5480
- ОС: Gentoo
Re: Проблемы с std::cout в Linux
shau-kote писал(а): ↑15.03.2013 20:27/dev/random писал(а): ↑14.03.2013 09:07Указывать следует либо корректную локаль (например, "ru_RU.UTF8"), либо пустую строку для автоопределения.
В смысле, в Linux? Или вообще?
Поскольку, когда я компилировал свой код в Windows, я поначалу тоже полагал, что нужно передать что-то вроде "utf-8", а оказалось, что рабочим является именно тот вариант, что я привёл.
Пример относится к Linux (точнее, к GNU, т.к. ядро тут ни при чём), а всё остальное - к стандарту. Набор локалей в каждой системе может быть свой. Единственный надёжный вариант - использовать автоопределение.
Да, он будет работать только если кодировка исходников и кодировка терминала совпадают. Лучше делать так, как я написал. А ещё лучше - использовать что-нибудь вроде gettext для многоязычности (в исходнике всё на английском, а переводы берутся из отдельных файлов). Выбор между "быстро" и "хорошо" - за вами.
-
shau-kote
- Сообщения: 417
- Статус: злобный хоббит
- ОС: Arch
Re: Проблемы с std::cout в Linux
/dev/random, спасибо, наконец-то разобрался. (:
-
Olej
- Сообщения: 659
- ОС: Fedora, Mint, Debian, QNX
-
Olej
- Сообщения: 659
- ОС: Fedora, Mint, Debian, QNX
Re: Проблемы с std::cout в Linux
"обычный char" замечательно пригоден
Но обычный char абсолютно непригоден для операций с контекстом строки: поиск, замещение и т.д. ... начиная с простейшей strlen() которая станет врать
И вот тут у вас есть на выбор 2-альтернативы (для хранения):
- использовать "широкие" символы wchar_t, которые являются (по POSIX) прямым изображением UNICODE кодировки UTF-32, и, естественно, каждый символ занимает 4 байта; для них есть все эквиваленты строчных функций: strchr() -> wcschr() и т.д. + операции: wcout << ... , wcin >> ...
- многобайтные представления, которые хоть и загружены в char[], но содержимое представлено именно в кодировке UTF-8 (т.е. тоже UNICODE, но в другой кодировке); они непригодны для непосредственной обработки строковыми функциями, но для них есть функции преобразований (mbtowc(), wctomb(), mblen(), mbrtowc(), wcrtomb(), mbrlen() и т.д.), для преобразования в wchat_t[] и обратно.
-
Olej
- Сообщения: 659
- ОС: Fedora, Mint, Debian, QNX
Re: Проблемы с std::cout в Linux
В Windows так ("Russian") называется локаль. Или, если совсем точно (не укорачивая) эта локаль в Windows записывается как "Russian_Russia.1251".
А KOI-8r, например, как "Russian_Russia.20866"
А в Linux локали называются совсем по другому.
Можете все их посмотреть сами:
Код: Выделить всё
bash-4.2$ locale -a | grep ru
ru_RU
ru_RU.iso88595
ru_RU.koi8r
ru_RU.utf8
...Так что явно записывать локаль в коде программы - дело дурное...