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

Разработка, программирование; c++, gcc, g++, gnu, mingw; winapi, windows; vscode.
Download Telegram
Dmitry Develop
image_2024-01-21_06-43-31.png
Продолжаю улучшать свой велосипед.

Было очень неудобно каждый раз явно приводить внутренний указатель к нужному типу:
((Type*)dynamicArray.memory)[index].member.

У меня массив и псевдоним для типа через using лежали в структуре, которая приходила в функцию по указателю.
Из-за этого и без того некороткая конструкция превращается в ещё более длинную:
((myStruct::Type*)myStruct->dynamicArray.memory)[index].member.
И такую длинную конструкцию приходилось писать на каждую запись или чтение.

Первым решением было создать переменную с автовыведением типа и инициализировать его преобразованным к нужному типу данных указателем:
auto array { (myStruct::Type*)myStruct->dynamicArray.memory };.
Без ключевого слова auto длина инструкии была бы в два раза больше.
Отлично, теперь для чтения и записи можно использовать обычный синтаксис, как для статических массивов:
array[0].member.

Однако, это всё будет работать до первого увеличения размера массива, так как указатель станет просто висячим (невалидным).
Вторым решением было использовать ссылку, но для таких махинаций она не работает, поэтому пришлось делать указатель на указатель, чтобы не хранить копию адреса, а получать всегда актуальный адрес из dynamicArray:
auto array { (myStruct::Type**)&myStruct->dynamicArray.memory };.
Но тогда array[0].member превратится в (*array[0]).member или в array[0][0].member, что вообще выглядит ужасно и непонятно.

Последнее и самое удачное решение, по моему мнению, было разделить управление динамической памятью и информацию о типе данных.
dynamicArray отвечает только за динамическую память, а компилятор за всё остальное, что касается типа данных и адресации:
dynamicArray arrayMemory { };
Type* array { };`

dynamicArrayAdd(&arrayMemory);
array[0].member = 10;

dynamicArrayAdd(&arrayMemory);
array[1].member = 20;


При создании массива указывается адрес переменной array (void**) для доступа к памяти с информацией о типе данных, и когда старый указатель становится невалидным, dynamicArray после выделения памяти записывает в неё новый валидный адрес.

ссылка на канал | ссылка на группу
У меня не с первого раза получилось реализовать в dynamicArray увеличение ёмкости с коэффициентом амортизации K = 1.5, хотя с K = 2 всё работало правильно, за исключением случая, если изначально capacity == 0.

При коэффициенте K = 1.5 предыдущий алгоритм совсем переставал работать, когда capacity ∊[0, 1], поэтому на этот случай нужно сделать проверку, если amortizedCapacity < newCapacity, то capacity = newCapacity, иначе capacity = amortizedCapacity, где:
newCapacity = capacity + 1;
amortizedCapacity = capacity * 3 / 2;
// 3 / 2 == 1.5


Понять работу алгоритма увеличения ёмкости мне очень помог этот сайт:
https://baemincheon.github.io/2021/05/16/cpp-std-vector-growth/
А на этом сайте можно увидеть примеры увеличения ёмкости с коэффициентами 2 и 1.5:
https://tylerayoung.com/2020/08/20/default-capacity-growth-rate-of-c-stdvector/

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

ссылка на канал | ссылка на группу
Dmitry Develop
image_2024-02-05_16-38-47.png
На фото для каждого из двух проектов я указал разные настройки, в данном случае разный размер шрифта.

В конфигурационных файлах моих проектов на разных языках программирования есть как повторяющиеся, так и отличающиеся настройки.
Часто, бывает, нужно работать сразу с несколькими проектами.
В vs code, когда открываешь проект, настройки можно определить только для всего проекта в подпапке .vscode, для подпапок настройки переопределить нельзя.

У меня давно была идея вынести общие настройки для всех проектов на уровень решения, а остальные настройки оставить или переопределить на уровне отдельного проекта.
Сегодня я нашёл способ как частично реализовать мою идею с разделением настроек.
Не знаю в какой версии это добавили, но в vs code есть такая функция, как рабочая область (workspace), это похоже на solution из IDE visual studio.
В рабочей области можно собрать несколько проектов, которые даже могут лежать в разных местах, и определить общие настройки для всего решения и отдельные для каждого проекта.
Какие проекты будут включены и их названия, а так же общие settings, tasks и launch определяются в файле рабочей области *.code-workspace.

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

https://code.visualstudio.com/docs/editor/multi-root-workspaces

ссылка на канал | ссылка на группу
👍1
Dmitry Develop
debugConsole.png
debugConsole: форматы и их вывод в консоли отладчика gdb.
vscodeWatch: форматы и их вывод в окне контрольные значения в редакторе кода vs code.

Сегодня я отлаживал windows SEH исключения, и мне нужно было в отладчике видеть код исключения в 16 системе счисления.

Помню, если в vs code после имени поставить запятую и число, он станет интерпретировать объект или адрес, как массив.
Немного поэкспериментировал и нашёл значения, которые действительно меняют представление числа во вкладке контрольные значения.

Немного поискал и почитал документацию.
Похоже, это всё благодаря поддержке от отладчика gdb.
Ещё заметил, что не все форматы из документации работают в vs code и наоборот в консоли отладчика.

Вывод в соответствии с типом данных в консоли gdb:
Синтаксис:
команда[/формат] объект

> -exec output code
code = 3221225477

Вывод в 2 системе счисления:
> -exec output/t code
code = 11000000000000000000000000000101

Вывод в 8 системе счисления:
> -exec output/o code
code = 030000000005

Вывод беззнакового в 10 системе счисления:
> -exec output/u 3221225477
code = 3221225477

Вывод знакового в 10 системе счисления:
> -exec output/d code
code = -1073741819

Вывод в 16 системе счисления:
> -exec output/x code
code = 0xc0000005

Вывод в виде адреса:
> -exec output/a code
code = 0xc0000005

Вывод в виде символа:
> -exec output/c code
code = 5 '\005'

Вывод в виде числа с плавающей точкой:
> -exec output/f code
code = -2.00000119

ссылка на канал | ссылка на группу
❤‍🔥2
Dmitry Develop
image_2024-02-12_01-55-21.png
Через отладчик gdb я смог изменить program counter (instruction pointer, rip) и сделать, что я хотел)).

Инструкция, где возникает исключение:
-exec set $pc = 0x7ff682701750

Проверка условия и сообщение об ошибке после неё:
-exec set $pc = 0x7ff682701757

Вот бы windows при EXCEPTION_CONTINUE_EXECUTION и некотором флаге мог сам продолжать выполнение со следующей инструкции.

Получилось именно так, как я и хотел:
1) возникает исключение
2) вызывается обработчик SEH исключения
3) в глобальную переменную сохраняется код исключения
4) исключения обрабатывается и выполнение программы продолжается
5) выполнение возвращается на инструкцию, где возникло исключение
6) я меняю rip на проверку условия
7) выводится ошибка STATUS_ACCESS_VIOLATION из моего кода на разыменование нулевого указателя
8) можно спокойно сохранять файлы журнала, делать другие действия и завершать программу

ссылка на канал | ссылка на группу
👍2
Dmitry Develop
image_2024-02-12_12-02-33.png
После моих манипуляций в конце программы почему-то возникают исключения (access violation и другие).

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

ctrl + shift + p -> open disassembly view, либо через ПКМ по файлу исходного кода -> open disassembly view.

ссылка на канал | ссылка на группу
👏1
Dmitry Develop
ссылка на канал | ссылка на группу
Продолжаю экспериментировать и исследовать механизм Vectored Exception Handler (windows SEH).

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

Чтобы в VEH возобновить исполнение программы и пропустить текущую инструкцию, которая привела к возникновению исключения, надо записать в регистр instruction pointer (на x64 это Rip, на x32 Eip) адрес начала следующей инструкции, но нужно знать размер пропускаемой инструкции в байтах.
Видимо, для этого придётся написать дисассемблер длин инструкций или найти готовое решение.

Можно просто увеличивать instruction pointer на 1 до тех пор, пока он не начнёт указывать на начало следующей инструкции, но я считаю это плохим решением.
Такой подход почти всегда будет приводить к возникновению новых ненужных (побочных) исключений, некоторые из них: STATUS_ACCESS_VIOLATION, EXCEPTION_ILLEGAL_INSTRUCTION.

ссылка на канал | ссылка на группу
👍1
Dmitry Develop
image_2024-02-15_14-33-05.png
Небольшое дополнение про контрольные значения в vs code.

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

Мне нужно было видеть текущий адрес в регистре Rip (instruction counter на x64) без постоянного отвлечения на консоль отладчика:
-exec output/x $pc

ссылка на канал | ссылка на группу
👍2
Dmitry Develop
makePortable.zip
С версии 1.25 от июня 2018 года в vs code появился портативный (переносной) режим.
https://code.visualstudio.com/updates/v1_25#_portable-mode

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

Доступен этот режим для всех трёх распространённых операционных систем: windows, linux и macOS и только для редактора, загружаемого в виде архива (*.zip, *.tar.gz).

Инструкция, как включить портативный режим для vs code или vs codium:
https://code.visualstudio.com/docs/editor/portable
https://github.com/VSCodium/vscodium/blob/master/docs/index.md#portable

Если пересказывать инструкцию кратко, то в папке установки нужно создать папку data, и внутри неё ещё три папки user-data, extensions и tmp (для macOS будет немного по-другому).

Выше вы можете скачать архив с расширением zip или 7-zip, в котором есть уже готовая иерархия пустых папок, содержимое которого надо просто разархивировать в корневую папку редактора.

ссылка на канал | ссылка на группу
👍3🎉1