Dmitry Develop
image_2024-02-19_16-53-18.png
Продолжаю переписывать проект с нуля.
Пересмотрел весь старый код проекта, определил алгоритм его работы, обратил внимание на трудности, неудобства и недостатки кода и подхода.
В новом проекте из-за вынесения функций и макросов в отдельные модули, для переиспользования кода и упрощения архитектуры, количество файлов уже немного пугает, ведь это только начало).
ссылка на канал | ссылка на группу
Пересмотрел весь старый код проекта, определил алгоритм его работы, обратил внимание на трудности, неудобства и недостатки кода и подхода.
В новом проекте из-за вынесения функций и макросов в отдельные модули, для переиспользования кода и упрощения архитектуры, количество файлов уже немного пугает, ведь это только начало).
ссылка на канал | ссылка на группу
👍2
Dmitry Develop
ссылка на канал | ссылка на группу
Как же мне нравится, когда код простой и явный.
(Ну, хотя бы для меня и по моим меркам)
Амортизационный коэффициент по-умолчанию для моего массива сделал 1.5, но можно в любой момент, даже между вставками, изменить его на любой другой.
Функция из byteAlgorithm работает, а чтобы компилятор не оптимизировал её код в вызов функции memcpy из стандартной библиотеки языка, использовал следующие pragma директивы препроцессора для gcc (mingw):
Жаль, что строгая типизация не позволяет неявно преобразовывать указатель на один тип данных в указатель на другой тип данных, когда мне важен именно адрес, а не тип данных по указателю.
Хотя, это потенциальное место для ошибок, надо бы подумать над тем, чтобы придумать специальные типы-псевдонимы через директивы using, чтобы явно выразить через них семантику.
ссылка на канал | ссылка на группу
(Ну, хотя бы для меня и по моим меркам)
Амортизационный коэффициент по-умолчанию для моего массива сделал 1.5, но можно в любой момент, даже между вставками, изменить его на любой другой.
Функция из byteAlgorithm работает, а чтобы компилятор не оптимизировал её код в вызов функции memcpy из стандартной библиотеки языка, использовал следующие pragma директивы препроцессора для gcc (mingw):
#pragma GCC push_options
#pragma GCC optimize ("-fno-tree-loop-distribute-patterns")
void byteCopy(uint8_t* from, uint8_t* to, int64_t size, status_s* status)
{
...
}
#pragma GCC pop_options
Жаль, что строгая типизация не позволяет неявно преобразовывать указатель на один тип данных в указатель на другой тип данных, когда мне важен именно адрес, а не тип данных по указателю.
Хотя, это потенциальное место для ошибок, надо бы подумать над тем, чтобы придумать специальные типы-псевдонимы через директивы using, чтобы явно выразить через них семантику.
ссылка на канал | ссылка на группу
👍4
Dmitry Develop
ссылка на канал | ссылка на группу
Как сломать отладку в vs code за 1 секунду?
Всего лишь попытаться вызвать функцию по её адресу в контрольных значениях)).
С чего всё началось и как я вообще додумался так сделать?
Когда пишешь на python, в контрольных значениях можно не только отслеживать уже созданные переменные, но и писать целые выражения и вызовы функций, которые будут выполняться прямо в runtime.
В моём модуле динамической памяти я поймал странное поведение.
Функция GetProcessHeap завершалась успешно, но GetLastError возвращала код 126: ERROR_MOD_NOT_FOUND (The specified module could not be found).
Из-за этого модуль сообщал о неуспешной операции.
Решил проверить последний код ошибки в самом начале main и получил тот же самый код, что мне показалось странным.
И я захотел начать отладку ещё до начала main где-то вstartfiles или crt mainCRTStartup.
А возвращаемое значение из функции GetLastError отслеживать в контрольных значениях, но что-то пошло не так...
ссылка на канал | ссылка на группу
Всего лишь попытаться вызвать функцию по её адресу в контрольных значениях)).
(unsigned long)(*0x7ffd10f15bf0)(void)()С чего всё началось и как я вообще додумался так сделать?
Когда пишешь на python, в контрольных значениях можно не только отслеживать уже созданные переменные, но и писать целые выражения и вызовы функций, которые будут выполняться прямо в runtime.
В моём модуле динамической памяти я поймал странное поведение.
Функция GetProcessHeap завершалась успешно, но GetLastError возвращала код 126: ERROR_MOD_NOT_FOUND (The specified module could not be found).
Из-за этого модуль сообщал о неуспешной операции.
Решил проверить последний код ошибки в самом начале main и получил тот же самый код, что мне показалось странным.
И я захотел начать отладку ещё до начала main где-то в
А возвращаемое значение из функции GetLastError отслеживать в контрольных значениях, но что-то пошло не так...
ссылка на канал | ссылка на группу
👍2
XL.jpeg
136.3 KB
Фотография не моя, взял её из фотографий отзывов бара failover на google maps.
ссылка на канал | ссылка на группу
ссылка на канал | ссылка на группу
Dmitry Develop
XL.jpeg
Я считаю, что программисту одного только написания кода недостаточно, важно поддерживать общение в IT сообществе не только в online, но и в offline.
Поэтому сегодня я буду на offline-вечеринке в IT баре failover.
В Санкт-Петербурге я буду 2-3 дня, буду рад встретить каждого).
ссылка на канал | ссылка на группу
Поэтому сегодня я буду на offline-вечеринке в IT баре failover.
В Санкт-Петербурге я буду 2-3 дня, буду рад встретить каждого).
ссылка на канал | ссылка на группу
👍2
Dmitry Develop
ссылка на канал | ссылка на группу
Делал небольшую инструкцию для человека, как в vs code выделить и редактировать несколько строк, и решил выложить её сюда.
Я очень часто использую данный подход для обработки большого количества строк в одинаковом формате, чтобы, например, вырезать какие-то названия.
ссылка на канал | ссылка на группу
Я очень часто использую данный подход для обработки большого количества строк в одинаковом формате, чтобы, например, вырезать какие-то названия.
ссылка на канал | ссылка на группу
Как бы мне реализовать главный цикл программы, чтобы в одном потоке:
1) обрабатывать сообщения windows
2) делать вычисления и отрисовку с нужной частотой
3) остальное время спать
4) даже во время сна обрабатывать новые сообщения
Является ли такая реализация через PeekMessageA:
Аналогом такой типичной реализации через GetMessageA?
Плохо только, что я не проверяю возвращаемое значение функции MsgWaitForMultipleObjects, но это только демонстрационный пример.
ссылка на канал | ссылка на группу
1) обрабатывать сообщения windows
2) делать вычисления и отрисовку с нужной частотой
3) остальное время спать
4) даже во время сна обрабатывать новые сообщения
Является ли такая реализация через PeekMessageA:
MSG message { };
while(true)
{
while(PeekMessageA(&message, nullptr, 0, 0, PM_REMOVE))
{
TranslateMessage(&message);
DispatchMessageA(&message);
}
if(message.message == WM_QUIT)
{
break;
}
MsgWaitForMultipleObjects(0, nullptr, false, INFINITE, QS_ALLINPUT);
}Аналогом такой типичной реализации через GetMessageA?
MSG message { };
while(GetMessageA(&message, nullptr, 0, 0))
{
TranslateMessage(&message);
DispatchMessageA(&message);
}Плохо только, что я не проверяю возвращаемое значение функции MsgWaitForMultipleObjects, но это только демонстрационный пример.
ссылка на канал | ссылка на группу
👏1
C MsgWaitForMultipleObjects, CreateWaitableTimerA и SetWaitableTimer у меня не получилось достигнуть более 60 FPS.
Windows, конечно, не RTOS, но и само разрешение системного таймера довольно низкое.
Можно его изменить при помощи timeBeginPeriod, но мне этот способ не нравится.
Зато этот просто способ даёт точную и стабильную частоту кадров).
Правда, этот способ впустую тратит такты процессора, создаёт повышенную нагрузку и тепловыделение.
В диспетчере задач будет большой процент использования ЦП.
Поэтому мне нужен другой способ или комбинированный предыдущий.
ссылка на канал | ссылка на группу
Windows, конечно, не RTOS, но и само разрешение системного таймера довольно низкое.
Можно его изменить при помощи timeBeginPeriod, но мне этот способ не нравится.
Зато этот просто способ даёт точную и стабильную частоту кадров).
// timeNow возвращает текущее время в наносекундах (windows QPC)
while(true)
{
...
static int64_t nextIter { };
int64_t now { };
timeNow(&now);
if(now >= nextIter)
{
InvalidateRect(window, nullptr, false);
const int64_t targetFPS { 240 };
nextIter = now + 1'000'000'000 / targetFPS;
}
...
}
Правда, этот способ впустую тратит такты процессора, создаёт повышенную нагрузку и тепловыделение.
В диспетчере задач будет большой процент использования ЦП.
Поэтому мне нужен другой способ или комбинированный предыдущий.
ссылка на канал | ссылка на группу
🤔1
Dmitry Develop
ссылка на канал | ссылка на группу
Необычная ошибка возникла при реализации off-screen bitmap rendering).
Как хорошо, что я уже давно не начинающий, поэтому никаких сложностей с отладкой не возникнет).
На экране рисуются две строки: 1) FPS, 2) задержка в наносекундах после отрисовки кадра.
Причина проблемы была в заполнении прямоугольника RECT функцией GetWindowRect вместо GetClientRect.
ссылка на канал | ссылка на группу
Как хорошо, что я уже давно не начинающий, поэтому никаких сложностей с отладкой не возникнет).
На экране рисуются две строки: 1) FPS, 2) задержка в наносекундах после отрисовки кадра.
Причина проблемы была в заполнении прямоугольника RECT функцией GetWindowRect вместо GetClientRect.
ссылка на канал | ссылка на группу
Dmitry Develop
winAPIWrapper.png
Как же мне надоело, что в winAPI вроде есть общий механизм обработки ошибок, но используется он не во всех функциях и не везде одинаково.
Где-то функция при успешном выполнении не выставляет
Где-то при неуспешном выполнении возвращается -1, любое отрицательное число, NULL или какое-то специальное значение вида 0xFFFFFFFF.
При написании кода просто невозможно за всеми этими тонкостями уследить, даже имея документацию перед глазами.
Поэтому всё-таки я сделаю небольшую обёртку над каждой функцией, чтобы в моём проекте был общий стиль обработки ошибок.
ссылка на канал | ссылка на группу
Где-то функция при успешном выполнении не выставляет
SetLastError(ERROR_SUCCESS), где-то выставляет.Где-то при неуспешном выполнении возвращается -1, любое отрицательное число, NULL или какое-то специальное значение вида 0xFFFFFFFF.
При написании кода просто невозможно за всеми этими тонкостями уследить, даже имея документацию перед глазами.
Поэтому всё-таки я сделаю небольшую обёртку над каждой функцией, чтобы в моём проекте был общий стиль обработки ошибок.
ссылка на канал | ссылка на группу
👍1
Dmitry Develop
usedWinapiFunctions.png
Пересмотрел все файлы проекта и выписал все используемые функции из winAPI, их получилось аж 82!
Уверен, если бы я был более внимательным, а также посмотрел ещё другие свои проекты, их стало бы гораздо больше.
А теперь вспоминаем проблемы, которые я описывал в предыдущем посте... поэтому возникновение идеи написания простой обёртки было делом времени.
Кстати, на фото перечислены 83 функции, но только 82 из них без повторов).
ссылка на канал | ссылка на группу
Уверен, если бы я был более внимательным, а также посмотрел ещё другие свои проекты, их стало бы гораздо больше.
А теперь вспоминаем проблемы, которые я описывал в предыдущем посте... поэтому возникновение идеи написания простой обёртки было делом времени.
Кстати, на фото перечислены 83 функции, но только 82 из них без повторов).
ссылка на канал | ссылка на группу
Dmitry Develop
windowsInterestingFact.png
Интересный факт в windows.
Когда у вас зависала программа или выполняла какую-то тяжёлую и долгую работу, тем самым не отвечав на сообщения от windows, такая программа и её окно получали статус не отвечает, но окно всё равно можно было свернуть или переместить.
Так вот, на самом деле вы взаимодействовали не с оригинальным окном, а его копией).
If a top-level window stops responding to messages for more than several seconds, the system considers the window to be not responding and replaces it with a ghost window that has the same z-order, location, size, and visual attributes. This allows the user to move it, resize it, or even close the application. However, these are the only actions available because the application is actually not responding. When in the debugger mode, the system does not generate a ghost window.
Ссылка на документацию, секция Remarks, самый последний абзац.
Кстати, эту функцию можно даже отключить:
https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-disableprocesswindowsghosting
Узнать, что период, через который окно получает статус неактивного, равен 5 секундам можно тут:
https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-ishungappwindow
ссылка на канал | ссылка на группу
Когда у вас зависала программа или выполняла какую-то тяжёлую и долгую работу, тем самым не отвечав на сообщения от windows, такая программа и её окно получали статус не отвечает, но окно всё равно можно было свернуть или переместить.
Так вот, на самом деле вы взаимодействовали не с оригинальным окном, а его копией).
If a top-level window stops responding to messages for more than several seconds, the system considers the window to be not responding and replaces it with a ghost window that has the same z-order, location, size, and visual attributes. This allows the user to move it, resize it, or even close the application. However, these are the only actions available because the application is actually not responding. When in the debugger mode, the system does not generate a ghost window.
Ссылка на документацию, секция Remarks, самый последний абзац.
Кстати, эту функцию можно даже отключить:
https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-disableprocesswindowsghosting
Узнать, что период, через который окно получает статус неактивного, равен 5 секундам можно тут:
https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-ishungappwindow
ссылка на канал | ссылка на группу
👍3🔥3