Dmitry Develop
176 subscribers
77 photos
35 videos
88 files
205 links
Этот канал в основном будет интересен новичкам в программировании и людям немного поопытнее.
Здесь я буду делиться своими новостями и достижениями в программировании.

Разработка, программирование; c++, gcc, g++, gnu, mingw; winapi, windows; vscode.
Download Telegram
Часть 1
часть 2

Все мы когда-нибудь сталкивались с таким явлением, как текст из иероглифов (крякозябр).

Причины, почему строки в одной кодировке выводятся в другой, могут быть разными.
Но почему отображаются всегда одни и те же кракозябры?
Ответ на этот вопрос довольно прост.

Кодировки бывают однобайтовые и многобайтовые.
Это значит, что для представления одного символа из строки требуется один или более байтов.

Представляйте кодировку, как очень большую таблицу, где для каждому символу присваивается уникальный порядковый номер в рамках этой кодировки.

Большинство кодировок являются совместимыми с ASCII (UTF-7), поэтому латиница, цифры и символы отображаются в разных кодировках правильно.

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

ссылка на канал | ссылка на группу
🔥2
В разработке моей небольшой библиотеки для работы с utf-8 строками остановился прогресс.
Хаотичное написание кода не помогло решить архитектурные вопросы и проблемы.
Поэтому я решил начать разработку с нуля, а именно с определения условий и требований к проекту.

Строка: это массив символов с 0 в конце (char string[] { 'S', 't', 'r', 'i', 'n', 'g', '\0'}).
Ввод и вывод данных происходит в виде строки.
Большая часть работы происходит со строками.
Строка закодирована по стандарту utf-8.

Цель проекта разработать следующий функционал:
операции над строками (копирование, конкатенирование, сравнение...),
конвертирование других типов данных из/в строку (stringFromInt, stringToInt),
конвертирование кодировки строки из/в utf-16 для OS windows.

Условия:
Си подобный API с минимальным использованием возможностей C++.
Разрешается делать C++ обёртку над Си API.
Язык программирования: C++20.
Компилятор: gcc x86_64 12.2.0


ссылка на канал | ссылка на группу
👍1
Dmitry Develop
Часть 1 часть 2 Все мы когда-нибудь сталкивались с таким явлением, как текст из иероглифов (крякозябр). Причины, почему строки в одной кодировке выводятся в другой, могут быть разными. Но почему отображаются всегда одни и те же кракозябры? Ответ на этот…
1 часть
2 часть

По этой причине, если вы только начали свой путь в программировании, пишите все строки в программе на латинице, чтобы проблемы с кодировкой вас не затронули.

В кодировке UTF-8, CP-1251, CP-866 и других латинская буква 'A' представляется { 65 }.
Однако кириллическая 'А' в UTF-8 { 208, 144 }, в CP-1251 { 192 }, в CP-866 { 128 }.

Более наглядно разницу в кодировании символов можете посмотреть в разделе "Таблица символов" на сайте adruino.

Вот так строка в UTF-8 будет отображаться в разных распространённых кодировках:
UTF-8
"Здравствуйте. Hello. +-*/012345"

UTF-16
"���4�@�0�2�A�B�2�C�9�B�5. Hello. +-*/012345"

CP-437
"Здравствуйте. Hello. +-*/012345"

CP-866
"╨Ч╨┤╤А╨░╨▓╤Б╤В╨▓╤Г╨╣╤В╨╡. Hello. +-*/012345"

CP-1251
"Здравствуйте. Hello. +-*/012345"

CP-1252
"Здрав�твуйте. Hello. +-*/012345"

ссылка на канал | ссылка на группу
👍1
Не могу придумать однозначные названия для свойств строки и названия параметров функций.

У строки есть 3 свойства: объём памяти, количество байтов, количество символов.
Вопрос в том, какое название выбрать для каждого свойства?

int A { 64 }; // размер памяти
int B { 12 }; // количество байтов
int C { 6 }; // количество символов

char string[A] = "Привет";
B = 12 = count({ 208, 159, 209, 128, 208, 184, 208, 178, 208, 181, 209, 130 });
C = 6 = count("Привет");


ссылка на канал | ссылка на группу
Что ж, размер строки в символах и байтах теперь можно получить.

Предыдущий вопрос остаётся открытым.
Как назвать: размер массива, количество байтов и символов в строке?

Где-то нужно указать размер памяти, где-то количество байтов.
size в зависимости от контекста может иметь разный смысл.

Допустим, есть у нас функция, которая читает ввод из консоли и записывает его в буфер определённого размера.
void consoleRead(char* string, int sayMyName);

sayMyName
может значить и размер строки в байтах, и размер памяти, может значить сколько символов мы хотим прочитать.

Либо функцию переделывать, либо думать над названием переменной.

ссылка на канал | ссылка на группу
Разрабатываю алгоритм работы функции на листочке).

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

ссылка на канал | ссылка на группу
👍2
Листочек и немного времени творят чудеса.

Функция, которая месяц назад всегда провоцировала access violation, сейчас написана с 0 и прекрасно работает.

stringCopy(destination, source, terminated);
Копирует строку source в destination.

Так же эта функция прекрасно копирует перекрывающиеся строки в отличии от strcpy, поэтому есть возможность копировать, например, конец строки в её начало или сдвигать символы строке.

Для этого сделана удобная обёртка
stringCopy(string, offset, terminated);

ссылка на канал | ссылка на группу
👍1
Вот так сейчас довольно просто в виде обёртки над stringCopy реализован в прошлом stringShift (Move), который сдвигает символы в строке.

Код моей библиотеки это наглядный пример принципа DRY (Don`t Repeat Yourself).

Весь функционал моей библиотеки разбит на много маленьких и самостоятельных функций (модулей).

И более сложный функционал составляется из этих маленьких модулей без лишнего повторения кода.

ссылка на канал | ссылка на группу
Пример реализации функции замены подстроки в строке.

ссылка на канал | ссылка на группу
Делаю тестирование каждой функции и задумываюсь, какая семантика должна быть у функции в зависимости от аргументов.

Некоторые рассматриваемые вопросы есть в комментариях в коде.

Я объединил реализацию stringShift и stringCopy только потому, что у них было очень много общего кода.

stringShift тоже копирует строки, как stringCopy.
Отличие между ними заключается в том, что первая умеет копировать перекрывающиеся строки (memmove из C).
Хотя использовался этот функционал только для сдвига символов в строке.

ссылка на канал | ссылка на группу
3
Как же мне нравится заниматься инфографикой).

Визуализация помогает наглядно увидеть принцип работы, вероятные ошибки и способ оптимизации алгоритма.

ссылка на канал | ссылка на группу
This media is not supported in your browser
VIEW IN TELEGRAM
Принцип работы копирования.

ссылка на канал | ссылка на группу
👍1
Ох, сколько же времени понадобится, чтобы сделать отладку каждой функции.

Параметров как-то многовато, но если спрятать повторяющиеся (string и capacity) в структуру String и вместо *status использовать return, станет получше.

Раньше у меня status был thread_local, и его не надо было явно передавать, чтобы гарантировать уникальную копию состояния для каждого потока.
Но это требует поддержки со стороны компилятора, а мне хочется попробовать сделать без неё.

stringCopy и stringShift я решил оставить самостоятельными функциями, так как у них немного разная логика.
stringShift в работе использует и может полагаться на offset, когда stringShift не может полагаться на разницу адресов (у меня выдавало разницу в миллиард).

В будущем напишу конвертер кодировок utf-8 <-> utf-16 и форматирование чисел).
1) stringToUtf16
2) stringFromUtf16
(Нужны только для OS windows)

3) stringFormatInt или через 3 параметр в stringFromInt

ссылка на канал | ссылка на группу
👍1
Тестирую сейчас каждую функцию из библиотеки.
На данный момент всё работает как и было задумано.

В процессе написания тестов заметил, что использовать мою библиотеку не особо удобно.
Нужно учитывать много низкоуровневых тонкостей и деталей реализации, чтобы работать со строкой.
Я хочу видеть строку, как массив символов вне зависимости от её кодировки и способа хранения.

Нужно пересмотреть способ работы с библиотекой и написать итераторы с функторами.
Тогда можно будет работать со строкой, как массивом символов, а не байтов.
Но и оставить возможность получить информацию по каждому символу: номер, количество байт, сам символ.

ссылка на канал | ссылка на группу
Это концепт stringIterateChar

Так будет гораздо проще работать со строкой, как с массивом символов.

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

ссылка на канал | ссылка на группу
Media is too big
VIEW IN TELEGRAM
Вот таким образом можно итерировать строку посимвольно.

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

ссылка на канал | ссылка на группу
Посмотрите предыдущий пост ещё раз, я его полностью переделал.

ссылка на канал | ссылка на группу
Я пока ещё только учусь, чтобы официально стать полноценным junior разработчиком, но мне недавно предложили одно дело...

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

Пожелайте мне удачи и успехов с моим первым серьёзным проектом).

ссылка на канал | ссылка на группу
👍7
1 часть
2 часть

vs code это редактор кода с поддержкой плагинов.
Для работы с C++ нужно установить C/C++ дополнение, отдельно скачать и установить компилятор, потом создать конфиги в папке проекта.

Я хотел поэкспериментировать с настройкой конфигов, поэтому создал пустой проект без них с единственным файлом main.cpp.

В пустом проекте почему-то исходный код успешно компилировался и отлаживался, хотя я ещё ничего не настраивал, я даже не указывал путь до компилятора нигде.
Мне это показалось слишком странным, поэтому я решил копнуть глубже.

Оказалось, что отладчик неявно ищет путь к известным компиляторам в переменных среды (PATH).
У меня в PATH как раз был указан путь к моему компилятору gcc.
Я эту строчку удалил, чтобы узнать, что произойдёт дальше.

После этого отладчик сообщал об ошибке
Unable to start debugging. The value of miDebuggerPath is invalid

ссылка на канал | ссылка на группу
1 часть
2 часть

Хорошо, решение этой проблемы довольно простое.
Я создал launch.json и написал минимально необходимый конфиг, а главное
"miDebuggerPath": "D:/gcc/bin/gdb.exe".

Теперь при отладке ошибка стала другой:
ERROR: Unable to start debugging. Unexpected GDB output from command "-exec-run". During startup program exited with code 0xc0000135.

С такой ошибкой я ещё ни разу не сталкивался, она сбила меня с толку.
Спустя некоторое время поисков, я не нашёл решения для моей ошибки.

Тогда я решил поискать похожие проблемы не по тексту ошибки, а коду 0xc0000135.
И о чудо, на github уже кто-то сталкивался с таким кодом ошибки.
Оказалось, что отладчик просто не может найти DLL необходимые программе С++ библиотеки, которые обычно лежат в папке с компилятором или в c:/windows/system32.

Изменил current working directory "cwd": "${workspaceFolder}" на "cwd": "D:/gcc/bin/", у меня всё заработало.
Изменять текущую рабочую папку программы не самая лучшая идея, это костыль, из-за этого могут происходить самые разные и неочевидные проблемы.
Так и оказалось, когда я попробовал создать файл test.txt, он создался в папке с компилятором, а не рядом с main.exe.

Есть правильных 2 решения:
1) в настройках windows добавить в PATH путь до компилятора.
2) временно изменить PATH через конфиг.

Так как я сторонник portable программ, которые работают без установки и изменения реестра, я выбрал для себя 2 решение.
"environment":
[
{
"name": "PATH",
"value": "%PATH%;D:/gcc/bin/"
}
]

ссылка на канал | ссылка на группу
🔥1
В последнее время с настроением у меня совсем беда.
Нет сил и желания заниматься даже программированием.
Наверное, это называется выгорание.
Надеюсь, arduino сможет вернуть мне настрой снова творить).

Заказал с Китая:
arduino nano v3 type-c
макетную плату
соединительные провода
20 RGB светодиодов
100 резисторов на 220 Ом
5 потенциометров на 10 кОм с ручкой

ссылка на канал | ссылка на группу
👍2