Dmitry Develop
ссылка на канал | ссылка на группу
Мой велосипед (реализация динамического массива) работает).
Делать его в Си стиле и через
Используя шаблоны можно написать более удобный и эффективный код, добавить перегрузку операторов, и способ использования никак не будет отличаться от статических массивов.
Только вместо
ссылка на канал | ссылка на группу
Делать его в Си стиле и через
void*, мне кажется, это плохая идея хотя бы потому, что это небезопасно и нет статической проверки типов.Используя шаблоны можно написать более удобный и эффективный код, добавить перегрузку операторов, и способ использования никак не будет отличаться от статических массивов.
Только вместо
push_back, как у std::vector, можно перегрузить оператор +=.dynamicArray<int> array { };
// array += 9901;
// array += 9902;
// array += 9903;
// array += 9904;
// array += 9905;
// array += 9906;
// array += 9907;
// array += 9908;
const int elementCount { 8 };
for(int i { }; i < elementCount; ++i)
array += 9901 + i;ссылка на канал | ссылка на группу
Dmitry Develop
image_2024-01-21_06-43-31.png
Продолжаю улучшать свой велосипед.
Было очень неудобно каждый раз явно приводить внутренний указатель к нужному типу:
У меня массив и псевдоним для типа через
Из-за этого и без того некороткая конструкция превращается в ещё более длинную:
И такую длинную конструкцию приходилось писать на каждую запись или чтение.
Первым решением было создать переменную с автовыведением типа и инициализировать его преобразованным к нужному типу данных указателем:
Без ключевого слова auto длина инструкии была бы в два раза больше.
Отлично, теперь для чтения и записи можно использовать обычный синтаксис, как для статических массивов:
Однако, это всё будет работать до первого увеличения размера массива, так как указатель станет просто висячим (невалидным).
Вторым решением было использовать ссылку, но для таких махинаций она не работает, поэтому пришлось делать указатель на указатель, чтобы не хранить копию адреса, а получать всегда актуальный адрес из
Но тогда
Последнее и самое удачное решение, по моему мнению, было разделить управление динамической памятью и информацию о типе данных.
При создании массива указывается адрес переменной array (
ссылка на канал | ссылка на группу
Было очень неудобно каждый раз явно приводить внутренний указатель к нужному типу:
((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 после выделения памяти записывает в неё новый валидный адрес.ссылка на канал | ссылка на группу
У меня не с первого раза получилось реализовать в
При коэффициенте
Понять работу алгоритма увеличения ёмкости мне очень помог этот сайт:
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/
ссылка на канал | ссылка на группу
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, когда открываешь проект, настройки можно определить только для всего проекта в подпапке
У меня давно была идея вынести общие настройки для всех проектов на уровень решения, а остальные настройки оставить или переопределить на уровне отдельного проекта.
Сегодня я нашёл способ как частично реализовать мою идею с разделением настроек.
Не знаю в какой версии это добавили, но в vs code есть такая функция, как рабочая область (workspace), это похоже на solution из IDE visual studio.
В рабочей области можно собрать несколько проектов, которые даже могут лежать в разных местах, и определить общие настройки для всего решения и отдельные для каждого проекта.
Какие проекты будут включены и их названия, а так же общие settings, tasks и launch определяются в файле рабочей области
Жаль, на уровне папки можно не все настройки переопределить, а так же настройки внутри подпапок проекта всё равно не будут работать.
Но в таком случае можно подпапку проекта добавить в рабочую область, а в проекте её скрыть.
Звучит, как костыльное решение, но если есть такая необходимость, оно будет работать.
https://code.visualstudio.com/docs/editor/multi-root-workspaces
ссылка на канал | ссылка на группу
В конфигурационных файлах моих проектов на разных языках программирования есть как повторяющиеся, так и отличающиеся настройки.
Часто, бывает, нужно работать сразу с несколькими проектами.
В 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:
Синтаксис:
Вывод в 2 системе счисления:
Вывод в 8 системе счисления:
Вывод беззнакового в 10 системе счисления:
Вывод знакового в 10 системе счисления:
Вывод в 16 системе счисления:
Вывод в виде адреса:
Вывод в виде символа:
Вывод в виде числа с плавающей точкой:
ссылка на канал | ссылка на группу
vscodeWatch: форматы и их вывод в окне контрольные значения в редакторе кода vs code.
Сегодня я отлаживал windows SEH исключения, и мне нужно было в отладчике видеть код исключения в 16 системе счисления.
Помню, если в vs code после имени поставить запятую и число, он станет интерпретировать объект или адрес, как массив.
Немного поэкспериментировал и нашёл значения, которые действительно меняют представление числа во вкладке контрольные значения.
Немного поискал и почитал документацию.
Похоже, это всё благодаря поддержке от отладчика gdb.
Ещё заметил, что не все форматы из документации работают в vs code и наоборот в консоли отладчика.
Вывод в соответствии с типом данных в консоли gdb:
Синтаксис:
команда[/формат] объект> -exec output codecode = 3221225477Вывод в 2 системе счисления:
> -exec output/t codecode = 11000000000000000000000000000101Вывод в 8 системе счисления:
> -exec output/o codecode = 030000000005Вывод беззнакового в 10 системе счисления:
> -exec output/u 3221225477code = 3221225477Вывод знакового в 10 системе счисления:
> -exec output/d codecode = -1073741819Вывод в 16 системе счисления:
> -exec output/x codecode = 0xc0000005Вывод в виде адреса:
> -exec output/a codecode = 0xc0000005Вывод в виде символа:
> -exec output/c codecode = 5 '\005'Вывод в виде числа с плавающей точкой:
> -exec output/f codecode = -2.00000119ссылка на канал | ссылка на группу
❤🔥2
Dmitry Develop
image_2024-02-12_01-55-21.png
Через отладчик gdb я смог изменить program counter (instruction pointer, rip) и сделать, что я хотел)).
Инструкция, где возникает исключение:
Проверка условия и сообщение об ошибке после неё:
Вот бы windows при EXCEPTION_CONTINUE_EXECUTION и некотором флаге мог сам продолжать выполнение со следующей инструкции.
Получилось именно так, как я и хотел:
1) возникает исключение
2) вызывается обработчик SEH исключения
3) в глобальную переменную сохраняется код исключения
4) исключения обрабатывается и выполнение программы продолжается
5) выполнение возвращается на инструкцию, где возникло исключение
6) я меняю rip на проверку условия
7) выводится ошибка STATUS_ACCESS_VIOLATION из моего кода на разыменование нулевого указателя
8) можно спокойно сохранять файлы журнала, делать другие действия и завершать программу
ссылка на канал | ссылка на группу
Инструкция, где возникает исключение:
-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.
ссылка на канал | ссылка на группу
Я задумался, могу ли я изменением регистра 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.
ссылка на канал | ссылка на группу
Моей целью является реализовать трансляцию конкретных исключений для конкретных случаев и функций обратно в место их возникновения, пропуская одну инструкцию или строку кода, чтобы использовать общий механизм обработки ошибок в проекте.
Все остальные случаи и исключения будут обрабатываться операционной системой по-умолчанию, и обычно это приводит к TerminateProcess.
Чтобы в VEH возобновить исполнение программы и пропустить текущую инструкцию, которая привела к возникновению исключения, надо записать в регистр instruction pointer (на x64 это Rip, на x32 Eip) адрес начала следующей инструкции, но нужно знать размер пропускаемой инструкции в байтах.
Видимо, для этого придётся написать дисассемблер длин инструкций или найти готовое решение.
Можно просто увеличивать instruction pointer на 1 до тех пор, пока он не начнёт указывать на начало следующей инструкции, но я считаю это плохим решением.
Такой подход почти всегда будет приводить к возникновению новых ненужных (побочных) исключений, некоторые из них: STATUS_ACCESS_VIOLATION, EXCEPTION_ILLEGAL_INSTRUCTION.
ссылка на канал | ссылка на группу
👍1