LINUX.ORG.RU
ФорумTalks

Как много стрингов имеется в C++

 , ,


0

3

Вольный перевод https://blogs.msmvps.com/gdicanio/2018/05/28/how-many-strings-does-c-have/ не претендующий на литературную точность.


(... OK, языковый адвокат придрался бы, посоветовав: «Как много строковых типов...», но я хотел более хитростный заголовок)

Если вы программируете на Python и видите нечто, заключённое в одинарные или двойные кавычки, у вас имеется стринг:


s = 'Connie'

Нечто похожее происходит в Java, со стринговыми литералами вроде «Connie», реализованными как экземпляры класса java.lang.String:

String s = "Connie";

Хорошо.

Теперь давайте (барабанная дробь) войдём в царство C++! И тут начинается веселье.

Итак, давайте рассмотрим эту простую строку кода на C++:

auto s1 = "Connie";

Каков тип s1?

std::string ? массив char[7] ? (эй, "Connie" - это шесть символов, плюс завершающий NULL)

... что-то другое?

Вы можете использовать свою любимую IDE и, наведя указатель мышки на имя переменной, получить выведенный тип. Visual Studio C++ IntelliSense намекает на то, что это const char*. Вау!

А что насчёт "Connie"s ?

auto s2 = "Connie"s;

Нет, это не множественное число от "Connie". И это не искаженный саксонский родительный падеж. Теперь s2 относится к типу std::string ! Спасибо тебе, operator""s включённый в C++14.

Мы уже закончили? Разумеется нет! Не забывайте - это C++!

Например у вас может иметься u8"Connie", который представляет юникодный UTF-8 литерал. И разумеется, нам необходимо обсуждение на StackOverflow для того, чтобы выяснить "Как u8-литералы должны работать".

А ещё не забудте о L"Connie", u"Connie" и U"Connie" которые представляют const wchar_t*, const char16_t* (закодировано в UTF-16) и const char32_t* (закодировано в UTF-32) соответственно.

Ну теперь мы закончили, правда? Ещё нет!

На самом деле вы можете сочетать приведённые выше префиксы со стандартным s-суффиксом, например: L"Connie"s - это std::wstring, а U"Connie"s - это std::u32string и так далее.

Закончили, правда? Ещё нет! На самом деле нам надо учесть ещё и сырые (raw) стринговые литералы. Например: R"(C:\Path\To\Connie)" который является const char* (константным символьным указателем) на “C:\Path\To\Connie” (что ж, это позволяет избавиться от кодирования '\' при помощи управляющей последовательности '\\').

Так же не забывайте о сочетании сырых стринговых литералов со всеми префиксами и s-суффиксом, разобранными выше. Например: LR"(C:\Path\To\Connie)", UR"(C:\Path\To\Connie)", LR"(C:\Path\To\Connie)"s, UR"(C:\Path\To\Connie)"s и так далее!

Ой и в добавок к стандартному классу std::string и прочим стандартным, основанным на std::basic_string, определениям строковых типов (таких как std::wstring, std::u16string, std::u32string и т.д.) имеются платформо/библиотечно зависимые классы, такие как CString, CStringA и CStringW в ATL/MFC, QString в Qt и wxString в wxWidgets.

Вау! Не удивлюсь, если я упустил какие-то другие вариации стрингов.

P.S. Со всем этим стринговым разнообразим (наверное слишком большим...), как насчёт добавления в стандартную библиотеку C++ некоторых удобных стринговых операций, как например обрезание пробелов или преобразование символов в заглавные или в строчные? При этом в стандартной библиотеке C++ уже имеются функции «для ракетостроения», такие как функции Бесселя. А ведь ещё в стародавние времена MFC там в CString уже были такие функции как Trim, MakeLower и MakeUpper и это далеко не весь список.

★★★★★

Последнее исправление: bbk123 (всего исправлений: 10)

Ответ на: комментарий от bbk123

отличие char8_t от char в том, что первый ещё и беззнаковый

Какой ужас! Спешите видеть — мужчина отличается от женщины потому, что он мужчина!

deep-purple ★★★★★
()
Ответ на: комментарий от praseodim

даже тогда где-то к концу 70-х давно надо было запилить нормальные строки и операции над ними

Не вижу проблемы в структуре с всего длвумя полями: дата и лен.

deep-purple ★★★★★
()
Ответ на: комментарий от fsb4000

is undefined if the argument’s value is neither representable as unsigned char

Аааа, т.е. передав голову вместо жопы, получить УБ это странно? Тебе случаем на пхп не пора? Там таких проблем нет.

deep-purple ★★★★★
()

Нечто похожее происходит в Java, со стринговыми литералами вроде «Connie», реализованными как экземпляры класса java.lang.String:

Так в Java же тоже дофига подобного?

Окроме String там есть ещё char[], Character[], CharSequence, StringBuffer, StringBuilder и т. д.

Ну и Multiline Strings вроде в новых версиях Java подвезли.

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

Не должны. Всё остальное из неё тоже можно выкинуть. Пусть у каждого будет свой собственный, самосборный, ни с чьим другим несовместимый велик.

anonymous-angler ★☆
()
Ответ на: комментарий от deep-purple

Не вижу проблемы в структуре с всего длвумя полями: дата и лен.

И тут сразу возникает куча нюансов, а какого размера должен быть этот «лен»? 1 байт мало, 2 не всегда хватит, 4 уже оверхед для большинства случае. И что делать с системными API, которые ожидают нуль-терминированные строки

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

Не возникает таких вопросов, если посмотреть на современные реализации std::string с их small string optimisation (которая для маленьких строк вообще не выделяет память на куче) и с_str (ну да, строки с нулями в середине несовместимы с системными API, это надо учитывать).

Ну да std::string сейчас - это 24 байта минимум (по 8 байт на указатель, текущую длину и фактический размер буфера).

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

Но ведь с transform-ом можно использлвать std::tolower из (std::locale) в ней таких ограничений по UB нет.

Да, но есть второй параметр, а std::transform будет передавать только один параметр.

template< class charT >
charT tolower( charT ch, const locale& loc );

Всё равно нужна или лямбда или функция-обёртка, чтобы передать какую-нибудь locale вторым параметром.

fsb4000 ★★★★★
()
Ответ на: комментарий от yu-boot

8 байт под длину, всё равно у тебя указатель должен быть по 8 байтам выровнен, так-то в структуре у тебя будет padding, даже если ты под длину 1 байт выделишь.

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

Так в Java же тоже дофига подобного?

В Java нифига подобного нет.

Окроме String там есть ещё char[], Character[], CharSequence, StringBuffer, StringBuilder и т. д.

Массивы char[] и Character[] никто как стринги не использует, да и не может. char[] в C и в Java - это совершенно разные сущности. А Character[] ты вообще врядли где либо встретишь.

Всё остальное - реализации интерфейса CharSequence. Стандартный стринг - это java.lang.String и в большенстве случаев его хватает. К тому же он неизменяемый. Когда требуется изменяемый, используют StringBuilder, до Java 5 StringBuffer. То есть по факту используются лишь String и StringBuilder и вовсе не из-за кодировок.

Ну и Multiline Strings вроде в новых версиях Java подвезли.

Всего лишь более удобная форма записи литералов. Это всё тот же java.lang.String

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

С - лучший! А жабисты душат девочек и меняют пол таблетками!

А сишники убивают русских жён.

bbk123 ★★★★★
() автор топика
Ответ на: комментарий от deep-purple

Мы закончили?

Да. На первом же предложении. Потому что вот это вот всё — не плюсовые и не сишные проблемы. Я, как сишник и хейтер плюсов, заявляю тебе это в полном здравии и сознании. Твой тред вообще не про ЯП, а про кучу говностандартов локалей, под которые ЯП вынужден подстраиваться.

Почему в Java таких проблем нет? Почему там догадались отделить внутренний формат хранения текста от преобразования его в ту или иную кодировку для чего-то внешнего? Unicode как стандарт появился в январе 1991 года. Первый стандарт C++ появился в 1998 году. Почему в C++ было решено использовать однобайтовый char внутри std::string ? Зато теперь мы имеем std::string std::u8string std::u16string std::u32string std::wstring Причём тут вообще локали? Вон в Java для поддержки кодировок есть отдельный класс - Charset. На внутреннее представление текста внутри String это вообще не влияет. А в C++ какой-то салат.

bbk123 ★★★★★
() автор топика
Ответ на: комментарий от deep-purple

Сишный char зачем-то сделали знаковым, а позже выяснилось, что это было ошибкой. Ошибку попытались исправить в C++20, но оказалось, что исправление ещё не готово для реального использования и следует подождать C++23, а так же поддерживающих этот стандарт компиляторов.

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

Стандартная библиотека языка не обязана включать в себя всё на свете.

kek

thunar ★★★★★
()

При этом в стандартной библиотеке C++ уже имеются функции «для ракетостроения», такие как функции Бесселя.

Это-то тут при чем? Остапа понесло, и не в ту степь.

seiken ★★★★★
()

Ну так строки это не просто

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

Видимо при том, что нехватка базовой функциональности в C++ стрингах выглядит ещё более странно, на фоне таких вещей, как функция Бесселя в стандартной библиотеке.

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

зато жаба жрёт память и тормозит

Неправда. Первые версии Java действительно имели некоторые проблемы, но уже давно это не является проблемой. И речь вообще не о тормозах и не о памяти, а о базовой функциональности в стандартной библиотеке.

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

Но ведь конвертация каждый раз туда и обратно во внутреннее представление строки не даётся бесплатно

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

Разумеется, как и вообще поддержка локалей, которая там уже есть. К тому же конвертация понадобится нечастно - лишь когда данные нужно переслать куда-то, где этот внутренний формат неизместен.

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

Но не UTF-16. На Linux каждый вывод будет происходить преобразование в кодировку платформы. То есть UTF-16 => UTF-8. На Windows будет сразу выводить, так как там UTF-16.

Или например в Pascal, строки в UTF-8, на Linux выводятся сразу. А на Windows будет происходить перевод в UTF-16, перед выводом. С версии fpc 3.0 это происходит автоматически, и скрыто от программиста.

Но раньше нужно было явно писать типа такого(можно и сейчас продолжать писать, чтобы сохранить совместимость с fpc 2.6 и например с Windows 98):

writeln(UTF8ToConsole('Для выхода нажмите ENTER'));

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

В Go строки в UTF-8 и никто не жалуется.

Я тебе больше скажу. В С++ можно использовать UTF-8 строки.

https://www.boost.org/doc/libs/develop/libs/nowide/doc/html/index.html

На Windows будет происходить конвертация, но в целом пофиг. Всё работает и кроссплатформенно.

Просто С++ даёт выбор. Ты можешь решить, что std::string это UTF-8, можешь решить что CP866, можешь KOI8-R. Всё зависит лишь от программиста, как он будет интерпретировать набор байт, какая это кодировка.

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

Но std::string - это не UTF-8. Для нормальной поддержки UTF-8 нужно использовать std::u8string но его поддержка не готова. И вообще, почему этот выбор не сделать в одном классе? Внутреннее представление строк неодинаковое даже в Java.

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

Аффтар так пишет, как будто разнообразие это что-то плохое

Двачую. Diversity сейчас в моде.

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

Может быть ты хотел сказать: «не для всего нужна стандартная библиотека»? Но работа со строками - это одна из базовых функциональностей любого языка высокого уровня и соответственно это должно находиться в стандартной библиотеке, а не размазываться на кучу велосипедов.

bbk123 ★★★★★
() автор топика

Вот из ОП и становится понятно, зачем людям QtCore.

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

CHAR_BIT не обязан равняться 8, правда лишь в не POSIX системах. Так же, является ли char знаковым или беззнаковым по умолчанию, стандартом не определено.

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

CHAR_BIT не обязан равняться 8

Так главное что он не может быть меньше, не?

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

А зачем?

Этого недостаточно для гарантий что char хватает для UTF-8?

utf8nowhere ★★★
()
Последнее исправление: utf8nowhere (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.