Forger 22 22 февраля, 2022 Опубликовано 22 февраля, 2022 · Жалоба 13 minutes ago, Arlleex said: Но разве этот switch-case нагляден? Да, если весь case в одну строку, то очень наглядно )) Но повторюсь, это скрыто внутри драйвера, отлажено и забыто. Больше туда лазить смысла нет. Quote А если там этих возможных вариантов будет сотня-тысяча? Для таких случаев применю просто тип данных без всяких перечислений и контроль границ с соотв ассертом. Например, драйвер для SerialPort (USART) Для CAN я описал конкретный случай, который не требует сложных конструкций. Нет смысла обобщать простые конструкции - значения скоростей для CAN можно сказать стандартизированы, их немного совсем. Поэтому switch-case вполне уместен. Quote На самом деле можно приводить миллион примеров, когда без явного cast-а лаконично не обойтись. Примеры. 1. Функция чтения занятого места в программной очереди (FIFO) Если очередь построена на базе шаблона, не привязана к конкретным типам данных, то все делается несколько проще :) Опять-таки тоже без cast. Quote 2. Запись адресов каких-то объектов в регистры периферии Да, с регистрами периферии и другой низкоуровневой "ботвой" по-другому действительно никак :( Но это тоже все можно скрыть внутри неких драйверов, отладить и забыть. Глаз мозолить не будут ) Quote 3. Использование функций с несовместимыми указателями А тут уже лучше работать со ссылками, а не указателями ) Я редко использую указатели как таковые. А, если применяю, то исключительно локально внутри функций или внутри драйверов. Цель - максимально ограничить их область видимости, т.к. указатель по мне - потенциально ОПАСНЫЙ объект. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 165 22 февраля, 2022 Опубликовано 22 февраля, 2022 · Жалоба 3 минуты назад, Forger сказал: Если очередь построена на базе шаблона, не привязана к конкретным типам данных, то все делается несколько проще. Опять-таки тоже без cast. А это как? Позиции чтения/записи все равно придется описывать вполне конкретными типами данных. Цитата А тут уже лучше работать со ссылками, а не указателями ) Так ведь в очередь я могу передавать вообще что угодно. "Обобщенную" ссылку (void &) ведь сделать нельзя. И в чем "опасность" указателя? А если мне надо записать в очередь целую кучу каких-то данных, размер которых заранее не известен? Не совсем понятна "безопасность" ссылки в этом отношении. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 22 22 февраля, 2022 Опубликовано 22 февраля, 2022 · Жалоба 16 minutes ago, Arlleex said: А это как? Позиции чтения/записи все равно придется описывать вполне конкретными типами данных. Наверно мы о разных очередях говорим )) Я имел ввиду вот такую очередь: template <class Item, uint32_t SIZE> class Queue { public: Queue() : head(0), tail(0), freeSize(SIZE) { } bool isPutDone(const Item & item) { ... } bool isGetDone(Item & item) { .... } void tryToGet(Item & item) { isGetDone(item); } ... Quote Так ведь в очередь я могу передавать вообще что угодно. "Обобщенную" ссылку (void &) ведь сделать нельзя. Нет, конечно! Такая самодеятельно строго запрещена. У меня очередь может быть только очередью объектов ОДНОГО типа, разных - нет. Разные уже можно упаковать внутрь самого объекта, добавив ему соотв. методы. Quote И в чем "опасность" указателя? В его непредсказуемости когда проект развивается. Я не раз наступал на грабли с указателями и потому их избегаю насколько это возможно. Quote А если мне надо записать в очередь целую кучу каких-то данных, размер которых заранее не известен? Для этого следует использовать другие конструкции. Например, разношерстность данных упаковать внутрь некого класса-контейнера, а уже в очередь добавлять экземпляры этих классов-контейнеров. Так сказать изолировать мух от котлет )) Quote Не совсем понятна "безопасность" ссылки в этом отношении. Ну, про "ссылки vs указатели" наверно тут уже нет смысла писать, это довольно популярно уже расписано в сторонней литературе )) Вот небольшая цитата со стековерфлоу: Quote Принципиальных отличий два: ссылка, в отличии от указателя, не может быть неинициализированной; ссылка не может быть изменена после инициализации. Отсюда и получаем плюсы и минусы использования того и другого: ссылки лучше использовать когда нежелательно или не планируется изменение связи ссылка → объект; указатель лучше использовать, когда возможны следующие моменты в течении жизни ссылки: ссылка не указывает ни на какой объект; ссылка указаывает на разные объекты в течении своего времени жизни. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 56 23 февраля, 2022 Опубликовано 23 февраля, 2022 · Жалоба Про различие static_cast и reinterpret_cast сказали выше - это очень разные "по силе" касты (и последствия от преобразований тоже разные), но С не различает их в своём синтаксисе. А смысл их такого громоздкого синтаксиса именно в том, чтобы они своим безобразным видом прямо-таки подсвечивали место потенциальной ошибки (там где компилятору велели "умыть руки" и не контролировать работы с типами). Каст на С в коде зачастую нетрудно пропустить, т.к. это обычное выражение с круглыми скобками, коими С/C++ злоупотребляют. А *_cast<...>() кроме того ещё и подсвечивается в программерских редакторах, т.к. являются ключевыми словоми языка. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Darth Vader 0 23 февраля, 2022 Опубликовано 23 февраля, 2022 (изменено) · Жалоба 10 часов назад, Forger сказал: Принципиальных отличий два: ссылка, в отличии от указателя, не может быть неинициализированной; ссылка не может быть изменена после инициализации. Этими же свойствами обладает константный указатель (не путать с указателем на константу). Например: char a; char * const ptr_a = &a; // создание и инициализация константного указателя на char Здесь указатель ptr_a нельзя оставить неинициализированным при его создании. Также, ему нельзя присвоить адрес иного объекта программы (нельзя изменить) т.к. он константный, т.е. неизменяемый. Вот тут приведён более широкий список различий ссылок и указателей. Изменено 23 февраля, 2022 пользователем Darth Vader Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 165 23 февраля, 2022 Опубликовано 23 февраля, 2022 · Жалоба Кстати да! Ссылка же должна указывать на объект в памяти (т.е. она не может быть NULL). У меня, например, есть функции, которые могут принимать NULL как вполне допустимый операнд s32 cFIFO::read(u8 dst[], u32 len) { // вычисление занятого места // и следующей позиции nxtRPos ... if(dst != NULL) { // чтение из FIFO в dst[] } rpos = nxtRPos; ... } Т.е. вызвав read(NULL, 10) мы просто говорим "прочитать 10 элементов вхолостую". А вот вызвав read(buf, 10) мы просим реально считать 10 элементов из FIFO в buf. Ссылка здесь не поможет. В общем, есть достоинства и недостатки и у указателей и у ссылок. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 22 23 февраля, 2022 Опубликовано 23 февраля, 2022 · Жалоба 5 minutes ago, Arlleex said: Т.е. вызвав read(NULL, 10) мы просто говорим "прочитать 10 элементов впустую". А какой в этом смысл? Это похоже на некий костыль или я чего-то не понимаю. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 165 23 февраля, 2022 Опубликовано 23 февраля, 2022 · Жалоба 1 минуту назад, Forger сказал: А какой в этом смысл? Это похоже на некий костыль или я чего-то не понимаю. Бывает нужно просто скипнуть какое-то количество данных в FIFO, так как они по какой-то причине оказались не нужны для обработки. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 22 23 февраля, 2022 Опубликовано 23 февраля, 2022 · Жалоба 2 minutes ago, Arlleex said: Бывает нужно просто скипнуть какое-то количество данных в FIFO, так как они по какой-то причине оказались не нужны для обработки. Для такого необычного случая я бы сделал отдельный метод для класса очереди, который делает именно это. В коде это выглядело бы очень наглядно именно по названию метода: s32 cFIFO::skip(u32 len) В вашем же случае в коде придется добавлять комментарий, иначе такое написание вводит в заблуждение. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 165 23 февраля, 2022 Опубликовано 23 февраля, 2022 · Жалоба 5 минут назад, Forger сказал: Для такого необычного случая я бы сделал отдельный метод для класса очереди, который делает именно это. Дело в том, что код read() и такой функции skip() будет на 99% одинаковый, и к сожалению, если в будущем захочется что-то исправить в одной (например, по причине бага), то нужно будет не забыть исправить этот код и в другой. Я стараюсь избегать такого подхода с дублированием кода (естественно, если накладные расходы крайне незначительны, а один лишний if() в read() как раз этот случай). Я думаю, в данном случае можно попробовать создать inline функцию в классе, которая будет вызывать внутри себя read(NULL, len). Ну либо другой способ: dst в функции read() задать NULL по умолчанию. Тогда вызов read(10) как бы намекает, что нужно прочитать 10 элементов в никуда. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 22 23 февраля, 2022 Опубликовано 23 февраля, 2022 · Жалоба 11 minutes ago, Arlleex said: Дело в том, что код read() и такой функции skip() будет на 99% одинаковый, и к сожалению, если в будущем захочется что-то исправить в одной (например, по причине бага), то нужно будет не забыть исправить этот код и в другой. Это очень просто реализуется - сделайте private метод, который сделан так как вам удобно, с кучей аргументов, если нужно. Его и вызывайте из public методов, чуть ли прямо не описании класса, чтобы не тащить реализацию в cpp файл. Очень наглядно и решает вашу "проблему", нет никакого дублирования кода. Я бы в итоге именно так сам и сделал ) 11 minutes ago, Arlleex said: Тогда вызов read(10) как бы намекает, что нужно прочитать 10 элементов в никуда. Это очень плохая практика - давать намеки! Я все же - сторонник конкретики, по крайней мере в коде :) Поэтому сделал бы просто метод skip, который внутри вызывал бы ваш "толстый", но уже private метод. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 165 23 февраля, 2022 Опубликовано 23 февраля, 2022 · Жалоба 6 часов назад, dxp сказал: А смысл их такого громоздкого синтаксиса именно в том, чтобы они своим безобразным видом... Угу, вот была же аккуратная функция с небольшим размахом строк... И тут на тебе Скрытый текст cSLCAN::eFlow cSLCAN::parseClosed(u8 buf[], u32 &len) const { u32 plen = 0; eFlow flow = eFlow::INCOMPLETE; if(len >= 2) { u8 ack = ERR; const u8 ch1 = buf[0], ch2 = buf[1]; if(ch1 == 'O') { if(ch2 == CR) { if(!can->open()) ack = OK; flow = eFlow::SYNC; } else flow = eFlow::UNSYNC; stx->write(&ack, 1); plen = 2; } else if(len >= 3) { const u8 ch3 = buf[2]; flow = eFlow::UNSYNC; plen = 1; if(ch1 == 'S') { if(ch3 == CR) { s32 br = hexToInt1(ch2); if(br >= 0 && !can->setBitRate(static_cast<cCAN::eBitRate>(br + 1))) ack = OK; flow = eFlow::SYNC; plen = 3; } } stx->write(&ack, 1); } } len = plen; return flow; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 56 24 февраля, 2022 Опубликовано 24 февраля, 2022 · Жалоба И сразу отлично видно потенциально проблемное место, на которое компилятор промолчит, и сразу видно, что к чему кастуется. Вот это: if(br >= 0 && !can->setBitRate((cCAN::eBitRate)(br + 1))) выглядит ничем не лучше, даже наоборот - нужно прилагать усилия, чтобы понять, что тут ручное преобразование типов, а не просто скобки для выделения приоритетов операций. И вдобавок тут может скрываться злобный reinterpret_cast, если, скажем, тип, к которому делается преобразование, например, указатель. static_cast это с ходу отловит. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 165 5 марта, 2022 Опубликовано 5 марта, 2022 · Жалоба Приветствую всех. Итак, вопрос следующий: а какой практический смысл в const-методах класса? Да, мы говорим компилятору, что мы этому методу передаем неявно class_type *const this. Т.е. при поытках изменить данные класса вылезет ошибка. Но тут же мы идем в описание этого класса и удаляем const у метода. Я еще понимаю, когда все методы класса - константные (хотя это сложно представить). Но когда класс - сборная солянка из const- и не-const-методов - какой смысл запрещать изменять данные всем этим const-методам? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 165 5 марта, 2022 Опубликовано 5 марта, 2022 · Жалоба И все-таки. Есть у меня незакрытый гештальт, который я уже пару месяцев назад пытался решить. Назначенная инициализация в C++. У меня в Keil-е C++11. Соответственно, при компиляции следующего кода вылазит предупреждение struct sHwCfg { struct sGPIO { u32 pclkEnPos; GPIO_TypeDef &hw; u8 pinNum : 4; }gpio[2]; struct sCAN { u32 pclkEnPos; CAN_TypeDef &hw; }can; }static const HwCfgTbl[] = { #define INIT(n, rxgpio, rxpin, txgpio, txpin, can) \ [static_cast<u32>(cCAN::eHwCfg::n)] = { \ {RCC_AHB1ENR_GPIO##rxgpio##EN, *GPIO##rxgpio, rxpin, \ RCC_AHB1ENR_GPIO##txgpio##EN, *GPIO##txgpio, txpin}, \ {RCC_APB1ENR_CAN##can##EN, *CAN##can}} INIT(CAN1_PA11_PA12, A, 11, A, 12, 1), INIT(CAN2_PB12_PB13, B, 12, B, 13, 2) #undef INIT }; sources/drivers/can.cpp(49): warning: array designators are a C99 extension [-Wc99-designator] Понятно, что компилятор не хочет, чтобы я "вручную" указывал элементы массива в списке инициализации. Но мне так удобнее читать код. CAN1_PA11_PA12, CAN2_PB12_PB13 - это enum-ы. Естественно, в этот enum могут добавляться новые значения, причем в любом месте. Соответственно, инициализируемый массив не должен от этого "рассинхронизироваться" с назначаемыми элементами инициализации. Тем более у меня массив этих структур - константный: положения всех элементов известны на этапе компиляции программы - ан-нет, все равно держи warning-иЯ уже готов тупо подавить конкретно этот warning, только вот как, чтобы еще не задавить остальные причастные warning-и? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться