std :: wstring VS std :: string

651

Я не могу понять различия между std::string и std::wstring. Я знаю, что wstring поддерживает широкие символы, такие как символы Unicode. У меня есть следующие вопросы:

  • Когда следует использовать std::wstring над std::string?
  • Может ли std::string удерживать весь набор символов ASCII, включая специальные символы?
  • Поддерживается ли std::wstring всеми популярными компиляторами С++?
  • Что такое "широкий характер"?
  • 10
    Набор символов ASCII не имеет большого количества «специальных» символов, наиболее экзотичным, вероятно, является `(обратная цитата). std :: string может содержать около 0,025% всех символов Unicode (обычно 8-битный символ)
  • 1
    Если под «специальным» вы подразумеваете символы от 128 до 255, которые зависят от используемой нормы, то да, они поддерживаются.
Показать ещё 5 комментариев
Теги:
string
unicode
wstring
c++-faq

12 ответов

903

<код > строкакод > ? <Код > wstringкод > ?

std:: string является basic_string на char и std:: wstring на wchar_t.

char vs. wchar_t

char должен содержать символ, обычно 1-байтовый символ. wchar_t должен содержать широкий символ, а затем все становится сложно: в Linux код wchar_t равен 4 байтам, а в Windows - 2 байта

как насчет Unicode, то?

Проблема заключается в том, что ни char, ни wchar_t напрямую не привязан к unicode.

В Linux?

Давайте возьмем ОС Linux: моя система Ubuntu уже знает о unicode. Когда я работаю с строкой char, она закодирована в UTF-8 (т.е. Unicode строка символов). Следующий код:

  #include <cstring>
#include <iostream>

int main (int argc, char * argv [])
{  const char text [] =    "olé"  ;

  std:: cout < "sizeof (char):" < sizeof (char) < std:: endl;  std:: cout < "текст:" < текст < std:: endl;  std:: cout < "sizeof (текст):" < sizeof (текст) < std:: endl;  std:: cout < "strlen (текст):" < < strlen (текст) < std:: endl;
  std:: cout < "text (bytes):";
  для (size_t я = 0, iMax = strlen (текст); я < iMax; ++ i)  {     std:: cout < "" < static_cast < unsigned int > (                             static_cast < unsigned char > (текст [i])                         );  }
  std:: cout < std:: endl < std:: endl;
  // - - -
  const wchar_t wtext [] = L    "olé"  ;
  std:: cout < "sizeof (wchar_t):" < < sizeof (wchar_t) < std:: endl;  //std:: cout <  "wtext:"  < wtext < std:: endl; < - ошибка  std:: cout < msgstr "wtext: НЕОБХОДИМО СОХРАНЯТЬСЯ." & Л; < std:: endl;  std:: wcout < L  "wtext:"  < wtext < станд:: епсИ;
  std:: cout < "sizeof (wtext):" < < sizeof (wtext) < std:: endl;  std:: cout < "wcslen (wtext):" < < wcslen (wtext) < std:: endl;
  std:: cout < "wtext (bytes):";
  для (size_t я = 0, iMax = wcslen (wtext); я < iMax; ++ i)  {     std:: cout < "" < static_cast < unsigned int > (                             static_cast < unsigned short > (wtext [i])                             );  }
  std:: cout < std:: endl < std:: endl;
  return 0;
}
Код>

выводит следующий текст:

  sizeof (char): 1
текст: olé
sizeof (текст): 5
strlen (текст): 4
текст (байты): 111 108 195 169

sizeof (wchar_t): 4
wtext: НЕОБХОДИМО РАЗРАБОТАТЬСЯ.
wtext: ol  
sizeof (wtext): 16
wcslen (wtext): 3
wtext (bytes): 111 108 233
Код>

Вы увидите, что текст "olé" в char действительно построен четырьмя символами: 110, 108, 195 и 169 (не считая конечного нуля). (Я рассмотрю код wchar_t как упражнение)

Итак, при работе с char в Linux вы обычно должны использовать Unicode, даже не зная об этом. И поскольку std::string работает с char, поэтому std::string уже готов к юникоду.

Обратите внимание, что std:: string, как и API-интерфейс C, рассмотрит строку "olé" , чтобы иметь 4 символа, а не три. Поэтому вы должны быть осторожны при усечении/игре с символами unicode, потому что некоторая комбинация символов запрещена в UTF-8.

В Windows?

В Windows это немного отличается. Win32 должен был поддерживать большое количество приложений, работающих с char и на разных кодировках/кодовые страницы, выпущенные во всем мире, до появления Юникода.

Поэтому их решение было интересным: если приложение работает с char, то символьные строки кодируются/распечатываются/отображаются на ярлыках GUI, используя локальную кодировку/кодировку на машине. Например, "olé" будет "olé" в локализованной на французском языке Windows, но будет что-то особенное на кириллической локализованной Windows ( "olй", если вы используете Windows-1251). Таким образом, "исторические приложения", как правило, все еще работают по-старому.

Для приложений на базе Unicode Windows использует wchar_t, который имеет ширину 2 байта и кодируется в UTF-16, который кодируется в кодировке Unicode на двухбайтовых символах (или, по крайней мере, в основном совместимом UCS-2, что почти то же самое, что и IIRC).

Приложения с использованием char называются "multibyte" (потому что каждый глиф состоит из одного или нескольких символов char s), тогда как приложения, использующие wchar_t называются "широкоформатными" (потому что каждый глиф состоит из одного или двух wchar_t). См. MultiByteToWideChar и WideCharToMultiByte Преобразование Win32 API для получения дополнительной информации.

Таким образом, если вы работаете в Windows, вы плохо хотите использовать wchar_t (если вы не используете фреймворк, скрывающий это, например GTK + или QT...). Дело в том, что за кулисами Windows работает с строками wchar_t, поэтому даже при использовании исторических API в wchar_t строки char будут отображаться символы char) например, SetWindowText (низкоуровневая функция API для установки метки в графическом интерфейсе Win32).

Проблемы с памятью?

UTF-32 имеет 4 байта на каждый символ, поэтому добавлять нечего, если только текст UTF-8 и текст UTF-16 будут всегда использовать меньше или одинаковый объем памяти, чем текст UTF-32 ( и обычно меньше).

Если проблема с памятью, то вы должны знать, чем для большинства западных языков, текст UTF-8 будет использовать меньше памяти, чем тот же самый UTF-16.

Тем не менее, для других языков (китайский, японский и т.д.) используемая память будет либо одинаковой, либо большей для UTF-8, чем для UTF-16.

В общем, UTF-16 будет в основном использовать 2 байта на каждый символ (если вы не имеете дело с какими-то эзотерическими языковыми глифами (Klingon? Elvish?), в то время как UTF-8 будет тратить от 1 до 4 байтов.

См. http://en.wikipedia.org/wiki/UTF-8 # Compared_to_UTF-16 для получения дополнительной информации.

Заключение

<я > 1. Когда я должен использовать std:: wstring над std:: string?

В Linux? Почти никогда (§).
В Windows? Почти всегда (§).
По межплатформенному коду? Зависит от вашего инструментария...

(§): если вы не используете инструментарий/фреймворк, говорящий иначе

2. Может ли std::string удерживать все ASCII-символы, включая специальные символы?

Примечание. std::string подходит для хранения "двоичного" буфера, где std:: wstring не является!

В Linux? Да.
В Windows? Доступны только специальные символы для текущего языка пользователя Windows.

Изменить (после комментария Johann Gerell): a std::string будет достаточно для обработки всех основанных на символах строк (каждый символ имеет число от 0 до 255). Но:

  • ASCII должен идти от 0 до 127. Высшие символы НЕ ASCII.
  • символ с 0 по 127 будет корректно проведен.
  • char от 128 до 255 будет иметь значение в зависимости от вашей кодировки (unicode, non-unicode и т.д.), но он сможет хранить все символы Unicode, если они закодированы в UTF-8.

<я > 3. Является std:: wstring, поддерживаемым почти всеми популярными компиляторами С++?

В основном, за исключением компиляторов на основе GCC, которые переносятся на Windows
Он работает на моем g++ 4.3.2 (под Linux), и я использовал Unicode API на Win32 с Visual С++ 6.

<я > 4. Что такое широкий символ?

В C/С++ это тип символа, написанный wchar_t, который больше, чем простой тип символа char. Предполагается, что он используется для ввода внутри символов, индексы (например, символы Unicode) больше 255 (или 127, в зависимости от...)

  • 3
    Hum. Я не знал, что Windows не соответствует спецификации POSIX в этом отношении. POSIX говорит, что wchar_t должен быть способен представлять «различные коды широких символов для всех членов самого большого набора символов, указанного среди локалей, поддерживаемых средой компиляции».
  • 3
    @gnud: Возможно, wchar_t должно было быть достаточно для обработки всех символов UCS-2 (большинства символов UTF-16) до появления UTF-16 ... Или, возможно, у Microsoft были другие приоритеты, кроме POSIX, например, предоставление простого доступа к Unicode без изменения кодированной страницы с использованием char на Win32.
Показать ещё 28 комментариев
50

Я рекомендую избегать std::wstring в Windows или в другом месте, за исключением случаев, когда это требуется интерфейсом или где-либо рядом с вызовами Windows API и соответствующими преобразованиями кодировки в качестве синтаксического сахара.

Мое мнение представлено в http://utf8everywhere.org, автором которого я являюсь.

Если ваше приложение не ориентировано на API, например, в основном приложение UI, предложение состоит в том, чтобы хранить строки Unicode в std :: string и кодироваться в UTF-8, выполняя преобразование рядом с вызовами API. Преимущества, изложенные в статье, перевешивают явное раздражение конверсии, особенно в сложных приложениях. Это вдвойне подходит для многоплатформенной и библиотечной разработки.

И теперь, отвечая на ваши вопросы:

  1. Несколько слабых причин. Он существует по историческим причинам, где считается, что широкополосные каналы являются надлежащим способом поддержки Unicode. Теперь он используется для интерфейса API, которые предпочитают строки UTF-16. Я использую их только в непосредственной близости от таких вызовов API.
  2. Это не имеет никакого отношения к std :: string. Он может содержать любую кодировку, которую вы вкладываете в нее. Вопрос только в том, как вы относитесь к этому контенту. Моя рекомендация - UTF-8, поэтому он сможет корректно хранить все символы юникода. Это обычная практика в Linux, но я думаю, что Windows-программы тоже должны это делать.
  3. Нет.
  4. Широкий характер - запутанное имя. В первые дни Unicode существовало убеждение, что символ может быть закодирован в два байта, отсюда и название. Сегодня это означает "любая часть персонажа, длина которой составляет два байта". UTF-16 рассматривается как последовательность таких пар байтов (aka Wide characters). Символ в UTF-16 принимает одну или две пары.
35

Итак, каждый читатель здесь должен иметь четкое представление о фактах, ситуации. Если нет, то вы должны прочитать paercebal исключительно полный ответ [btw: thanks!].

Мой прагматический вывод потрясающе прост: все, что С++ (и STL) "кодирование символов" существенно нарушено и бесполезно. Обвините его в Microsoft или нет, это все равно не поможет.

Мое решение, после глубокого изучения, много разочарований и последующего опыта заключается в следующем:

  • соглашайтесь с тем, что вы должны нести ответственность за свои материалы для кодирования и преобразования (и вы увидите, что большая часть его довольно тривиальная)

  • используйте std::string для любых кодированных строк UTF-8 (всего лишь typedef std::string UTF8String)

  • согласитесь, что такой объект UTF8String является просто тупым, но дешевым контейнером. Никогда не обращайтесь к ним и/или не манипулируйте ими непосредственно (без поиска, замены и т.д.). Вы могли бы, но вы действительно просто действительно не хотите тратить свое время на написание алгоритмов манипуляции текста для многобайтовых строк! Даже если другие люди уже делали такие глупые вещи, не делайте этого! Будь как будет! (Ну, есть сценарии, где это имеет смысл... просто используйте библиотеку ICU для них).

  • используйте std:: wstring для кодированных строк UCS-2 (typedef std::wstring UCS2String) - это компромисс и уступка беспорядку, введенная WIN32 API). UCS-2 достаточно для большинства из нас (подробнее об этом позже...).

  • использовать экземпляры UCS2String всякий раз, когда требуется доступ к символьным символам (чтение, манипулирование и т.д.). Любая обработка на основе символов должна выполняться в N-многобайтовом представлении. Это просто, быстро и легко.

  • добавить две служебные функции для конвертирования между UTF-8 и UCS-2:

    UCS2String ConvertToUCS2( const UTF8String &str );
    UTF8String ConvertToUTF8( const UCS2String &str );
    

Конверсии просты, google должен помочь здесь...

Что это. Используйте UTF8String везде, где важна память, и для всех входов/выходов UTF-8. Используйте UCS2String везде, где строка должна анализироваться и/или обрабатываться. Вы можете конвертировать между этими двумя представлениями в любое время.

Альтернативы и улучшения

  • конверсии из однобайтовых кодировок символов (например, ISO-8859-1) могут быть реализованы с помощью простых таблиц перевода, например. const wchar_t tt_iso88951[256] = {0,1,2,...}; и соответствующий код для преобразования в UCS2 и из него.

  • если UCS-2 недостаточно, чем переключиться на UCS-4 (typedef std::basic_string<uint32_t> UCS2String)

ICU или другие библиотеки Unicode?

Для продвинутых материалов.

  • 0
    Черт, нехорошо знать, что встроенной поддержки Unicode нет.
  • 0
    @Frunsi, мне любопытно узнать, пробовал ли ты Glib :: ustring и если да, что ты думаешь?
Показать ещё 14 комментариев
22
  • Если вы хотите иметь широкие символы, хранящиеся в вашей строке. wide зависит от реализации. Visual С++ по умолчанию имеет значение 16 бит, если я правильно помню, в то время как настройки GCC по умолчанию зависят от цели. Здесь 32 бит. Обратите внимание: wchar_t (широкий тип символа) не имеет ничего общего с юникодом. Он просто гарантировал, что он может хранить все элементы самого большого набора символов, поддерживаемые реализацией его локалями, и, по крайней мере, до тех пор, пока char. Строки unicode можно сохранить в std::string с помощью кодировки utf-8. Но это не будет понимать смысл кодов Unicode. Поэтому str.size() не даст вам количество логических символов в вашей строке, а просто количество элементов char или wchar_t, хранящихся в этой строке /wstring. По этой причине пользователи обложек gtk/glib С++ разработали класс Glib::ustring, который может обрабатывать utf-8.

    Если ваш wchar_t имеет длину 32 бита, вы можете использовать utf-32 как кодировку Юникода, и вы можете хранить и обрабатывать строки юникода, используя фиксированную (utf-32 фиксированную длину) кодировку. Это означает, что ваша функция wstring s.size() вернет правильное количество элементов wchar_t и логических символов.

  • Да, char всегда имеет длину не менее 8 бит, что означает, что он может хранить все значения ASCII.
  • Да, все основные компиляторы поддерживают его.
  • 0
    Мне интересно о # 2. Я думал, что 7 бит будет технически действительным тоже? Или требуется иметь возможность хранить что-либо после 7-битных символов ASCII?
  • 1
    да, Джалф c89 определяет минимальные диапазоны для базовых типов в своей документации limit.h (для unsigned char, это 0..255 мин) и чисто двоичной системы для целочисленных типов. это следует за char, unsigned char и Sign char имеют минимальную длину в 8 бит. C ++ наследует эти правила.
Показать ещё 6 комментариев
5

Я часто использую std::string для хранения символов utf-8 без каких-либо проблем. Я сердечно рекомендую это делать, когда взаимодействую с API, который также использует utf-8 как родной тип строки.

Например, я использую utf-8 при взаимодействии моего кода с интерпретатором Tcl.

Основная оговорка - длина std::string, это больше не количество символов в строке.

  • 1
    Хуан: Вы имеете в виду, что std :: string может содержать все символы Юникода, но длина будет сообщаться неправильно? Есть ли причина, по которой он сообщает неверную длину?
  • 3
    При использовании кодировки utf-8 один символ Unicode может состоять из нескольких байтов. Вот почему кодировка utf-8 меньше при использовании в основном символов из стандартного набора ascii. Вам нужно использовать специальные функции (или свернуть свои собственные), чтобы измерить количество символов Юникода.
Показать ещё 7 комментариев
3
  • 10
    std :: string может содержать 0 отлично (будьте осторожны, если вы вызываете метод c_str ())
  • 3
    И, строго говоря, символ не обязательно должен быть 8 битами. :) Ваша ссылка в # 4 является обязательной для прочтения, но я не думаю, что она отвечает на вопрос. Широкий символ не имеет ничего общего с юникодом. Это просто более широкий характер. (Насколько шире зависит от ОС, но обычно 16 или 32 бит)
Показать ещё 1 комментарий
2

Приложения, которые не удовлетворяются только 256 различными символами, имеют опции либо с использованием широких символов (более 8 бит), либо с кодировкой переменной длины (многобайтовая кодировка в терминологии С++), например, UTF-8. Широким символам обычно требуется больше места, чем кодирование с переменной длиной, но они быстрее обрабатываются. Многоязычные приложения, которые обрабатывают большие объемы текста, обычно используют широкие символы при обработке текста, но конвертируют его в UTF-8 при хранении на диске.

Единственное различие между string и a wstring - это тип данных сохраняемых символов. Строка хранит char, размер которой не менее 8 бит, поэтому вы можете использовать строки для обработки, например. ASCII, ISO-8859-15 или UTF-8. В стандарте ничего не говорится о наборе символов или кодировке.

Практически каждый компилятор использует набор символов, первые 128 символов которого соответствуют ASCII. Это также относится к компиляторам, использующим кодировку UTF-8. Важно помнить, что при использовании строк в UTF-8 или какой-либо другой кодировке переменной длины индексы и длины измеряются в байтах, а не в символах.

Тип данных wstring равен wchar_t, размер которого не определен в стандарте, за исключением того, что он должен быть как минимум равным char, обычно 16 бит или 32 бита. wstring может использоваться для обработки текста в реализации, определенной широкосимвольной кодировкой. Поскольку кодировка не определена в стандарте, преобразовать между строками и wstrings непросто. Нельзя предположить, что wstrings также имеет кодировку с фиксированной длиной.

Если вам не нужна поддержка нескольких языков, вам может быть хорошо, если вы используете только обычные строки. С другой стороны, если вы пишете графическое приложение, часто бывает, что API поддерживает только широкие символы. Тогда вы, вероятно, захотите использовать те же самые широкие символы при обработке текста. Имейте в виду, что UTF-16 является кодировкой переменной длины, что означает, что вы не можете принять length(), чтобы вернуть количество символов. Если API использует кодировку с фиксированной длиной, такую ​​как UCS-2, обработка становится легкой. Преобразование между широкими символами и UTF-8 сложно сделать переносимым образом, но, опять же, API вашего пользовательского интерфейса, вероятно, поддерживает преобразование.

  • 0
    Итак, перефразируя первый абзац: приложению, требующему более 256 символов, необходимо использовать многобайтовую кодировку или кодирование Maybe_multibyte.
  • 0
    Обычно 16- и 32-битные кодировки, такие как UCS-2 и UCS-4, не называются многобайтовыми. Стандарт C ++ различает многобайтовые кодировки и широкие символы. В широком представлении символов используется фиксированное число (обычно более 8) битов на символ. Кодировки, которые используют один байт для кодирования наиболее распространенных символов и несколько байтов для кодирования остальной части набора символов, называются многобайтовыми кодировками.
Показать ещё 2 комментария
1
  • когда вы хотите использовать строки Unicode, а не просто ascii, полезно для интернационализации
  • да, но он не очень хорошо работает с 0
  • не знает о том, что не делает
  • Широкий символ - это специфический для компилятора способ обработки представления фиксированной длины символа Юникода, для MSVC это 2-байтовый символ, для gcc я понимаю, что это 4 байта. и +1 для http://www.joelonsoftware.com/articles/Unicode.html
  • 1
    2. Std :: string может содержать символ NULL просто отлично. Он также может содержать utf-8 и широкие символы.
  • 0
    @Juan: Это снова привело меня в замешательство. Если std :: string может хранить символы Юникода, что особенного в std :: wstring?
Показать ещё 4 комментария
1

1) Как упоминалось Грегом, wstring полезна для интернационализации, когда вы будете выпускать свой продукт на других языках, кроме английского

4) Проверьте это для широкого символа http://en.wikipedia.org/wiki/Wide_character

0

Здесь есть очень хорошие ответы, но я думаю, что есть несколько вещей, которые я могу добавить в отношении Windows/Visual Studio. Это основано на моем опыте с VS2015. В Linux, в основном, ответ заключается в том, что везде используется кодировка std::string UTF-8. В Windows/VS он становится более сложным. Вот почему. Windows ожидает, что строки будут храниться с использованием char который будет закодирован с использованием кодовой страницы локали. Это почти всегда набор символов ASCII, за которым следуют 128 других специальных символов в зависимости от вашего местоположения. Позвольте мне просто сказать, что это не только при использовании Windows API есть три других основных места, где эти строки взаимодействуют со стандартным C++. Это строковые литералы, выводятся в std::cout с помощью << и передача имени файла в std::fstream.

Я буду впереди здесь, что я программист, а не специалист по языку. Я ценю, что USC2 и UTF-16 не совпадают, но для моих целей они достаточно близки, чтобы быть взаимозаменяемыми, и я использую их как таковые здесь. Я не уверен, что Windows использует, но мне вообще не нужно знать. Я сказал UCS2 в этом ответе, поэтому извините заранее, если я расстроил кого-либо своим незнанием этого вопроса, и я счастлив изменить его, если у меня все получится.

Строковые литералы

Если вы вводите строковые литералы, содержащие только символы, которые могут быть представлены вашей кодовой страницей, тогда VS хранит их в вашем файле с 1 байт на кодировку символов на основе вашей кодовой страницы. Обратите внимание: если вы измените свою кодовую страницу или передадите свой источник другому разработчику с использованием другой кодовой страницы, я думаю (но не проверял), что персонаж окажется другим. Если вы запустите свой код на компьютере, используя другую кодовую страницу, я не уверен, изменит ли этот символ.

Если вы введете любые строковые литералы, которые не могут быть представлены вашей кодовой страницей, тогда VS попросит вас сохранить файл как Unicode. Затем файл будет закодирован как UTF-8. Это означает, что все символы без ASCII (включая те, которые находятся на вашей кодовой странице) будут представлены двумя или более байтами. Это означает, что если вы передадите свой источник кому-то другому, источник будет выглядеть одинаково. Однако, прежде чем передать источник компилятору, VS преобразует кодированный текст UTF-8 в кодированный текст кода, и любые символы, отсутствующие на кодовой странице, заменяются на ? ,

Единственный способ гарантировать правильное представление строкового литерала в Юникоде в VS - это предшествовать строковому литералу с помощью L что делает его широким строковым литералом. В этом случае VS преобразует кодированный текст UTF-8 из файла в UCS2. Затем вам нужно передать этот строковый литерал в конструктор std::wstring или вам нужно преобразовать его в utf-8 и поместить его в std::string. Или, если вы хотите, вы можете использовать функции Windows API для его кодирования с помощью кодовой страницы, чтобы поместить его в std::string, но тогда вы также можете не использовать широкоформатный литерал.

станд :: соиЬ

При выводе на консоль с помощью << вы можете использовать только std::string, а не std::wstring и текст должен быть закодирован с использованием вашей кодовой страницы локали. Если у вас есть std::wstring то вы должны преобразовать его, используя одну из функций Windows API, и любые символы, не входящие в вашу кодовую страницу, заменяются ? (возможно, вы можете изменить персонажа, я не помню).

std :: fstream имена файлов

ОС Windows использует UCS2/UTF-16 для своих имен файлов, поэтому независимо от вашей кодовой страницы вы можете иметь файлы с любым символом Unicode. Но это означает, что для доступа или создания файлов с символами, не входящими в вашу кодовую страницу, вы должны использовать std::wstring. Другого пути нет. Это специальное расширение Microsoft для std::fstream поэтому, вероятно, оно не будет компилироваться в других системах. Если вы используете std :: string, вы можете использовать только имена файлов, которые включают только символы в вашей кодовой странице.

Ваши варианты

Если вы просто работаете в Linux, то, вероятно, вы так далеко не дошли. Просто используйте UTF-8 std::string всюду.

Если вы просто работаете с Windows, просто используйте UCS2 std::wstring везде. Некоторые пуристы могут сказать, что использовать UTF8 затем конвертировать, когда это необходимо, но зачем беспокоиться о хлопот.

Если вы - кросс-платформа, то это беспорядок, чтобы быть откровенным. Если вы пытаетесь использовать UTF-8 повсюду в Windows, тогда вам нужно быть очень осторожным с вашими строковыми литералами и выводить на консоль. Вы можете легко повредить свои строки там. Если вы используете std::wstring всюду на Linux, то у вас может не быть доступа к широкой версии std::fstream, поэтому вам нужно сделать преобразование, но нет никакого риска коррупции. Поэтому я считаю, что это лучший вариант. Многие не согласятся, но я не одинок - это путь, который используют wxWidgets, например.

Другим вариантом может быть typedef unicodestring как std::string в Linux и std::wstring в Windows, а также макрос под названием UNI(), который префикс L на Windows и ничего не работает в Linux, затем код

#include <fstream>
#include <string>
#include <iostream>
#include <Windows.h>

#ifdef _WIN32
typedef std::wstring unicodestring;
#define UNI(text) L ## text
std::string formatForConsole(const unicodestring &str)
{
    std::string result;
    //Call WideCharToMultiByte to do the conversion
    return result;
}
#else
typedef std::string unicodestring;
#define UNI(text) text
std::string formatForConsole(const unicodestring &str)
{
    return str;
}
#endif

int main()
{

    unicodestring fileName(UNI("fileName"));
    std::ofstream fout;
    fout.open(fileName);
    std::cout << formatForConsole(fileName) << std::endl;
    return 0;
}

было бы хорошо на любой платформе, я думаю.

ответы

Итак, чтобы ответить на ваши вопросы

1) Если вы программируете для Windows, то все время, если кросс-платформу, возможно, все время, если вы не хотите иметь дело с возможными проблемами с коррупцией в Windows или писать какой-то код с определенными платформенными #ifdefs чтобы обойти различия, если просто используя Linux, то никогда.

2) Да. Кроме того, в Linux вы можете использовать его для всех Unicode. В Windows вы можете использовать его только для всех юникодов, если вы решите вручную кодировать с помощью UTF-8. Но API Windows и стандартные классы C++ ожидают, что std::string будет закодирована с использованием кодовой страницы локали. Это включает в себя все ASCII плюс еще 128 символов, которые меняются в зависимости от кодовой страницы, которую компьютер настроил для использования.

3) Я так считаю, но если нет, то это просто простой typedef из 'std :: basic_string', используя wchar_t вместо char

4) Широкий символ - это тип символа, который больше стандартного char типа 1 байт. В Windows это 2 байта, в Linux - 4 байта.

  • 1
    Что касается «Однако перед передачей исходного кода компилятору VS преобразует кодированный в кодировке UTF-8 текст в кодированный код, а любые символы, отсутствующие в кодовой странице, заменяются символом?». -> Я не думаю, что это так, когда компилятор использует кодировку UTF-8 (используйте /utf-8 ).
  • 0
    Я не знал об этом в качестве варианта. По этой ссылке docs.microsoft.com/en-us/cpp/build/reference/… кажется, что в свойствах проекта нет флажка для выбора, вы должны добавить его в качестве дополнительного параметра командной строки. Хорошее место!
0

Хороший вопрос! Я думаю, что DATA ENCODING (иногда CHARSET) - это MEMORY EXPRESSION МЕХАНИЗМ, чтобы сохранять данные в файл или передавать данные по сети, поэтому Я отвечаю на этот вопрос следующим образом:

1.Когда я должен использовать std:: wstring над std::string?

Если платформа программирования или функция API являются однобайтными, и мы хотим обрабатывать или анализировать некоторые данные в формате unicode, например, читать из файла Windows.REG или сетевого 2-байтового потока, мы должны объявить std:: wstring переменная, чтобы легко их обрабатывать. например: wstring ws = L "中国 a" (6 октетов: 0x4E2D 0x56FD 0x0061), мы можем использовать ws [0] для получения символов '中' и ws [1] для получения символов '国' и ws [2] получить символ "a" и т.д.

2.Can std::string сохранить весь набор символов ASCII, включая специальные символы?

Да. Но обратите внимание: American ASCII означает, что каждый октет 0x00 ~ 0xFF для одного символа, включая печатный текст, такой как "123abc & * _ &" и вы сказали специальный, в основном напечатайте его как ".". избегайте запутывания редакторов или терминалов. И некоторые другие страны расширяют свою собственную кодировку "ASCII", например. Китайцы, используют 2 октета для обозначения одного персонажа.

3.Is std:: wstring поддерживается всеми популярными компиляторами С++?

Может быть, или в основном. Я использовал: VС++ 6 и GCC 3.3, YES

4.Что такое "широкий символ"?

широкий символ в основном указывает использование 2 октетов или 4 октета для хранения всех символов стран. 2 октета UCS2 представляет собой репрезентативную выборку, а далее, например, Английский 'a', его память составляет 2 октета 0x0061 (vs в ASCII 'память 1 октет 0x61)

-3

Когда вы НЕ используете широкоформатные символы?

Когда вы пишете код до 1990 года.

Очевидно, я переворачиваюсь, но на самом деле, это 21-й век. 127 символов уже давно перестали быть достаточными. Да, вы можете использовать UTF8, но зачем беспокоиться о головных болях?

  • 16
    @dave: я не знаю, какую головную боль создает UTF-8, которая больше, чем у Widechars (UTF-16). в UTF-16 у вас также есть многосимвольные символы.
  • 0
    Проблема в том, что если вы где-нибудь, кроме англоговорящей страны, вы НЕ ДОЛЖНЫ использовать wchar_t. Не говоря уже о том, что в некоторых алфавитах гораздо больше символов, чем вписывается в байт. Мы были там, в DOS. Кодовая страница шизофрении, нет, спасибо, не более ..
Показать ещё 5 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню