Arlleex 167 30 июня Опубликовано 30 июня · Жалоба 37 минут назад, Forger сказал: кмк тут похоже действует привычное правило - не переборщить и не перемудрить )) Так и с дефайнами желательно не борщить и не мудрить) Я, например, давным-давно завел файлик с макросами для упрощения жизни, и уже изредка их, но пополняю. В основном это всякие вычисления битовых масок, сдвигов, позиций битов, занесения новых значений в битовое поле регистра и т.д. Не люблю, когда в исходнике овердофига всяких, по сути, типовых операций засовывания чиселок туда-сюда по регистрам в нужные позиции. Например, вместо void RCC_IRQHandler(void) { u32 const cir = RCC->CIR; if ((cir & (RCC_CIR_HSERDYIE | RCC_CIR_HSERDYF)) == (RCC_CIR_HSERDYIE | RCC_CIR_HSERDYF)) // (o.O) -> (~.@) вырви глаз ... } if ((cir & (RCC_CIR_PLLRDYIE | RCC_CIR_PLLRDYF)) == (RCC_CIR_PLLRDYIE | RCC_CIR_PLLRDYF)) ... } } я пишу void RCC_IRQHandler(void) { u32 const cir = RCC->CIR; if (IS_BIT_SET(cir, RCC_CIR_HSERDYIE | RCC_CIR_HSERDYF)) { ... } if (IS_BIT_SET(cir, RCC_CIR_PLLRDYIE | RCC_CIR_PLLRDYF)) { ... } } Читаемо? Гораздо лучше чем оригинал. А в коде обычное дело - проверять установленность нескольких битов одновременно. Другой пример: нужно битовое поле шириной 10 бит, начиная с позиции 13 бита. В голове, обычно "твою ж ты, это что там за маска - эээм, так, 10 - 2 = 8 бит так, это 0xFF, а еще 2 бита это 0x3, т.е. 0x3FF и сдвигаем на 13". А у меня есть простой макрос u32 mask = BIT_MSK(10) << 13; Или например, когда в стандартном файле периферии битовые поля заданы дефайнами, а позиций нет - (особенно в старых ревизиях) #define APB_CLOCK_DIV 0x07F80000u И начинается - чтобы записать туда предделитель 5 надо или открывать калькулятор, или написать нечто такое монструозно-плохочитаемое CPU->DIV = (CPU->DIV & ~APB_CLOCK_DIV) | (APB_CLOCK_DIV & -APB_CLOCK_DIV) * 5; // (-_O) а я просто напишу UPD_FLD(CPU->DIV, APB_CLOCK_DIV, 5); И много еще всякого удобного) Я для себя принял, что такие макросы я буду использовать для слишком низкоуровневых операций с какими-то регистрами и битовыми представлениями, когда сам язык в альтернативном варианте не гарантирует нужного поведения. В случае, например, с битовыми полями структур это очень актуально. Вместо битовых полей структур приходится елозить по конкретному мемберу этой структуры с помощью сдвигов и масок, когда расположение этих полей и их порядок, выравнивание и т.д. очень важны для приложения. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 22 30 июня Опубликовано 30 июня · Жалоба 7 minutes ago, Arlleex said: IS_BIT_SET Так эти же макросы уже реализованы и есть внутри заголовочных файлов cmsis, SET_BIT, CLEAR_BIT, READ_BIT и др. вот например выборка из stm32g0xx.h: /** @addtogroup Exported_macros * @{ */ #define SET_BIT(REG, BIT) ((REG) |= (BIT)) #define CLEAR_BIT(REG, BIT) ((REG) &= ~(BIT)) #define READ_BIT(REG, BIT) ((REG) & (BIT)) #define CLEAR_REG(REG) ((REG) = (0x0)) #define WRITE_REG(REG, VAL) ((REG) = (VAL)) #define READ_REG(REG) ((REG)) #define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK))) стараюсь использовать "стандартные", так код проще переносить и сопровождать. Самодельных - минимум Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 167 30 июня Опубликовано 30 июня · Жалоба 2 минуты назад, Forger сказал: Так эти же макросы уже реализованы и есть внутри заголовочных файлов cmsis, SET_BIT, CLEAR_BIT, READ_BIT и др. стараюсь использовать "стандартные", так код проще переносить и сопровождать. Самодельных - минимум Я раньше тоже думал, что стандартных мне хватит. Но не хватило)) Вернее, их банально не оказалось при программировании под другой МК (там вообще не CMSIS). Да и закладываться на поставляемые кем-то макросы в своих исходниках считаю злом) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 22 30 июня Опубликовано 30 июня · Жалоба Just now, Arlleex said: Да и закладываться на поставляемые кем-то макросы в своих исходниках считаю злом) если сам h-файл, где они содержатся, обязательный для включения в исходник (дефайны регистров), то ничего в этом плохого не вижу если добавлять чужие инклуды чисто ради чужих дефайнов, то это конечно нездоровая ситуация 2 minutes ago, Arlleex said: Вернее, их банально не оказалось при программировании под другой МК (там вообще не CMSIS). тогда, проще самому накидать аналогичный файл, или поискать готовый на гитхабе. наличие готовых cmsis файлов под камень это уже норма, так сказать правило хорошего тона )) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 167 30 июня Опубликовано 30 июня · Жалоба 2 минуты назад, Forger сказал: если сам h-файл, где они содержатся, обязательный для включения в исходник (дефайны регистров), то ничего в этом плохого не вижу если добавлять чужие инклуды чисто ради чужих дефайнов, то это конечно нездоровая ситуация Допустим, задачу проверки установленности двух битов одновременно макрос READ_BIT не решает. MODIFY_REG выглядит все равно костыльным - т.е. надо думать, на сколько двигать аргумент. Кошмар. Вот я и вспомнил, почему не стал их применять)) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 22 30 июня Опубликовано 30 июня · Жалоба 14 minutes ago, Arlleex said: Я раньше тоже думал, что стандартных мне хватит. А мне хватает, стараюсь не использовать макросы, тем более чужие. На замену есть constexpr и локальные лямбда функции (но по чесноку лямбды использую лишь для простых обработчиков прерываний): Spoiler class CommunicationLib: public Communication { virtual void connectSignals() final; virtual void run() final; class Thread : public OS::Thread<kCommunicationStackSize> { .... private: virtual void initialize() final; virtual void body() final; Hardware::CAN::Frame rxFrame; Hardware::CAN::Frame txFrame; Hardware::Pin<PA12> pinCAN_TX; Hardware::Pin<PA11> pinCAN_RX; Hardware::PortCAN1 port{pinCAN_RX, pinCAN_TX}; OS::Semaphore semaphoreFrameRx{"CAN.RxFrame"}; ... void CommunicationLib::Thread::initialize() { .... port.initialize(); static auto interruptRX0 = [this]() { port >> rxFrame; semaphoreFrameRx.signal(); }; // статическая ламбда обработчика пререываний, чтобы не добавлять соотв метод в класс потока Delegate<void()> vectorRX0 = interruptRX0; port.installVectorRX0(vectorRX0); port.irq.RX0.messagePending.enable(); port.setBitrate(kCommunicationBaudrate); port.run(); 9 minutes ago, Arlleex said: Допустим, задачу проверки установленности двух битов одновременно макрос READ_BIT не решает. а я никогда так не делаю, избегаю да и нет такой нужды, такие макросы у меня используются только в низкоуровеных библиотеках, методы которых вызываются однократно или очень редко, поэтому наглядность и читаемость кода важнее, пусть он даже занимает чуть больше места в памяти (крохи). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 167 30 июня Опубликовано 30 июня · Жалоба 4 минуты назад, Forger сказал: А мне хватает, стараюсь не использовать макросы, тем более чужие. На замену есть constexpr и локальные лямбда функции (но по чесноку лямбды использую лишь для простых обработчиков прерываний): Лямбды и constexpr вычисляются в процессе компиляции файла. Дефайны мои - они для другого: чтобы сократить кучу однотипной писанины изначально. Макросы здесь только лишь в роли текстового "упрощателя" синтаксиса. Потому что когда таких строчек в типичном драйвере периферии под сотню - можно и скобочку лишнюю потерять, или тильду забыть, или да мало ли что еще. И все это происходит до компиляции как таковой. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 22 30 июня Опубликовано 30 июня · Жалоба 1 minute ago, Arlleex said: Макросы здесь только лишь в роли текстового "упрощателя" синтаксиса. Потому что когда таких строчек в типичном драйвере периферии под сотню - можно и скобочку лишнюю потерять, или тильду забыть, или да мало ли что еще. И все это происходит до компиляции как таковой. все верно )) поэтому минимум макросов и только самые "доверенные" )) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 167 30 июня Опубликовано 30 июня · Жалоба 6 минут назад, Forger сказал: а я никогда так не делаю, избегаю да и нет такой нужды, Я выше там привел обработчик прерывания RCC_IRQ_Handler(), в котором как раз такая нужда есть 😃 Не понимаю, как Вы никогда не делали так и не испытывали необходимости в таких проверках) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 22 30 июня Опубликовано 30 июня · Жалоба 12 minutes ago, Arlleex said: Не понимаю, как Вы никогда не делали так и не испытывали необходимости в таких проверках) не припомню такого прошелся поиском по своим разным проектам строкой "if (READ_BIT", везде проверка ОДНОГО бита (или группы битов, если они записаны в ОДИН соотв дефайн). Хотя ничего не мешается проверять сразу два и более, но это ухудшает читаемость Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 167 30 июня Опубликовано 30 июня · Жалоба 14 минут назад, Forger сказал: не припомню такого прошелся поиском по своим разным проектам строкой "if (READ_BIT", везде проверка ОДНОГО бита (или группы битов, если они записаны в ОДИН соотв дефайн). Хотя ничего не мешается проверять сразу два и более, но это ухудшает читаемость Именно. А проверка if (READ_BIT(mask)) проверит, установлен ли как минимум (хотя бы) один из битов в mask. А это даже синтаксически плохо выглядит - по аналогии с проверкой одного бита можно "случайно" подумать, что в случае с группой бит он проверит, что все они установлены) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 22 30 июня Опубликовано 30 июня · Жалоба 16 minutes ago, Arlleex said: А это даже синтаксически плохо выглядит честно говоря, так не заморачиваюсь, эти макросы у меня используются только в низкоуровневом коде в моих библиотеках для работы с регистрами камней, такие раз отладил и забыл, в юзер коде таких макросов нет, а если есть - то это костыль/метка, что нужно от них избавится, при отладке проекта это нормально, это как прихватить сваркой в нескольких местах, чтобы конструкция держалась, а уже потом нормально проварить швы целиком )) 20 minutes ago, Arlleex said: А проверка if (READ_BIT(mask)) проверит, установлен ли как минимум (хотя бы) один из битов в mask. можно руками расписать, чтобы биты проверялись не группой а по отдельности, если это нужно для наглядности, но это опять - вкусовщина пошла )) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 167 30 июня Опубликовано 30 июня · Жалоба Не ну это уже просто сюр)) Допустим, есть классы class Base { u32 value; }; class Derived : public Base { }; Оказывается, нет гарантий, что даже если в наследнике нет никаких дополнительных мемберов или виртуальных функций, sizeof(Base) == sizeof(Derived). Да что этот язык вообще гарантирует? Как вообще на нем писать низкоуровневые вещи, к тому же достаточно абстрактные для переноса между разными компиляторами/платформами? Типа, проверил на своем железе - все ок. Отдал попользоваться кому-то еще - у него все сломалось. Умно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Sh@dow 0 30 июня Опубликовано 30 июня (изменено) · Жалоба Как вообще на нем писать низкоуровневые вещи? Знать что компилятор гарантирует а что нет. В вашем случае sizeof(Base) == sizeof(Derived) не обязано быть верным. Так как компилятор имеет право подравнивать адреса для ускорения времени доступа. Изменено 30 июня пользователем Sh@dow Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 22 30 июня Опубликовано 30 июня · Жалоба 1 hour ago, Arlleex said: Отдал попользоваться кому-то еще - у него все сломалось. Это проблемы того, кто им пользуется )) Я свой низкоуровневый код не выкладываю куда попало на гитхаб. Если там кто-то начнет что-то править, то нет никаких гарантий, что у меня в существующих проектах чужая самодеятельность в этом коде не вызовет проблем. Нееее, меня такой расклад ни разу не устраивает! В своем низкоуровеновом коде использую статические классы/структуры (упрощенные синглтоны), шаблоны очень активно и замечательную незаменимую вещь - namespace. 1 hour ago, Arlleex said: Да что этот язык вообще гарантирует? язык тут не причем, это - всего лишь ИНСТРУМЕНТ, а все дело в том, кто и как им пользуется )) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться