Arlleex 178 10 сентября, 2023 Опубликовано 10 сентября, 2023 · Жалоба Все чаще замечаю мнения (и тут, и на иностранных ресурсах), что Си макросы в том виде, котором они есть, когда-нибудь должны быть уничтожены в C++ Типа, все в плюсах можно переписать на более праведном шаблонном метапрограммировании с контролем типов и т.д. Я бы хотел в этом убедиться. Начну с простого. У меня есть макросы и вспомогательные макрос-функции для определения бита (бит-маски) по его номеру #define B0 bit(0) #define B1 bit(1) #define B2 bit(2) ... #define B63 bit(63) т.е., например, B5 это будет (1u << 5). Все эти определения B0...B63 у меня находятся в файле macros.h, который я дописываю/изменяю крайне редко. Т.е. macros.h, можно сказать, платформо-независимый (абстрактный). В начале этого заголовочника у меня подключается build_opts.h, в котором как раз я определяю некие платформо-зависимые вещи, на основе которых "рабочие" макросы разворачиваются в правильный вид. Поэтому для идентичности использования макросов при кодировании под разные архитектуры мне нужно поправить только один файл build_opts.h. Так вот, в build_opts.h у меня задаются длины (хвосты) литеральных целых, т.к. это напрямую диктуется разрядностью системы. Для Cortex-M4, например, #define INT_LITERAL_SUFFIX_OCT_0 #define INT_LITERAL_SUFFIX_OCT_1 #define INT_LITERAL_SUFFIX_OCT_2 #define INT_LITERAL_SUFFIX_OCT_3 #define INT_LITERAL_SUFFIX_OCT_4 ll #define INT_LITERAL_SUFFIX_OCT_5 ll #define INT_LITERAL_SUFFIX_OCT_6 ll #define INT_LITERAL_SUFFIX_OCT_7 ll И теперь, самый интересный фокус - определение макроса bit() #define bit(num) (cond_concat_2((num) / 8 == 0, 1u, INT_LITERAL_SUFFIX_OCT_0, \ cond_concat_2((num) / 8 == 1, 1u, INT_LITERAL_SUFFIX_OCT_1, \ cond_concat_2((num) / 8 == 2, 1u, INT_LITERAL_SUFFIX_OCT_2, \ cond_concat_2((num) / 8 == 3, 1u, INT_LITERAL_SUFFIX_OCT_3, \ cond_concat_2((num) / 8 == 4, 1u, INT_LITERAL_SUFFIX_OCT_4, \ cond_concat_2((num) / 8 == 5, 1u, INT_LITERAL_SUFFIX_OCT_5, \ cond_concat_2((num) / 8 == 6, 1u, INT_LITERAL_SUFFIX_OCT_6, \ cond_concat_2((num) / 8 == 7, 1u, INT_LITERAL_SUFFIX_OCT_7, \ 1ull)))))))) << (num)) Здесь по номеру бита вычисляется номер физического октета, а по нему, в зависимости от архитектурных особенностей (литеральных хвостов в данном случае), получаемая битовая маска правильного типа. Сам фокус в использовании вспомогательного макроса "тернарно-условной конкатенации" cond_concat_2(cond, a, b, c), который на этапе компиляции вычисляет условие cond, если оно истинно, делает конкатенацию токенов a##b, и это будет результатом этого макроса, а в противном случае (если cond == 0), cond_concat_2() вернет токен c. Казалось бы, в реализации cond_concat_2() можно было применить операцию тернарного условия ?:, однако в таком случае bit() с любым параметром имел бы тип ull, что совершенно некорректно. Я обратился к документации на различные компиляторы и обнаружил, что в широко распространенном GCC и CLang разработчики об этом позаботились, реализовав макрос __builtin_choose_expr(). Это прямо то, что нужно! Примечание: жаль, конечно, что на текущий момент разработчики не разрешают вносить в невыбранное выражение синтаксически неверное выражение (либо несуществующий токен препроцессора), хотя, вроде как, обещались, что подумают над этим. Значит, вот cond_concat_2() #define cond_concat_2(cond, a, b, expr2) __builtin_choose_expr(cond, concat_2(a, b), expr2) С реализацией склейки concat_2(), надеюсь, все понятно, это стандартный двойной разворот #define concat_2(...) _concat_2(__VA_ARGS__) ... #define _concat_2(a, b, ...) a##b Теперь я точно знаю, что bit(30) развернется в (1u << 30) и это будет правильно, а bit(60) развернется в (1ull << 60) и при использовании в различных выражениях со смешанными целыми типами данных у меня не будет вылезать куча побочных варнингов из-за неявного приведения типов и т.д. Очень удобно. Да, можно было определить Bx напрямую склейкой 1u с нужным хвостом, но я посчитал это громоздким, можно ошибиться, да и у меня есть и другие макросы, которые построены по похожему принципу, т.к. так читаются легче. Как такое реализовать в C++? Чем, по сути, будет являться определение Bx? Это будет некий объект класса или как? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 10 сентября, 2023 Опубликовано 10 сентября, 2023 · Жалоба 3 hours ago, Arlleex said: Как такое реализовать в C++? Если именно такое, то это будут такие же костыли. Я бы исходил из задачи, а не решения, что мол надо на плюсах и все тут. Какая вообще задача? В общем К слову, работу с пинами сделал иначе, на плюсах конечно, никаких макросов, но есть крохотный оверхед по озу, но мне это до лампочки в моих задачах. Читаемость куда ценнее )) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 10 сентября, 2023 Опубликовано 10 сентября, 2023 · Жалоба 11 минут назад, Forger сказал: Если именно такое, то это будут такие же костыли. Не ну а какое еще)) Мы ж в программах не абстрактными классами машем, в конце концов. Просто меня порой удивляет мнение некоторых товарищей, мол "так никто не пишет", "в C++ все проектируется в других категориях мышления" и другой уже невыносимый бред)) Такое чувство, что код там не пишется, а философствуется)) Мы же, в конечном счете, все равно оперируем где-то битами, где-то масками и т.д. В Си я показал, как использую. Хотел увидеть магию шаблонных супер-пупер крутых плюсов, где ничтожные макросы оказались бы действительно ничтожными. Цитата Я бы исходил из задачи, а не решения, что мол надо на плюсах и все тут. Задача, как всегда, донельзя проста: написать некие тривиальные синтаксические "облегчалки", которыми потом сыпать в реальном коде. Т.е. действительно от макросов вообще можно уйти. Цитата Впрочем именно так у себя и делаю. На плюсах, есть крохотный оверхед по озу, но мне это до лампочки в моих задачах. Читаемость куда ценнее )) Это как? Откуда оверхед? У меня на этих макросах оверхед (еще и по ОЗУ) == 0, его просто нет. На любых уровнях оптимизации. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 10 сентября, 2023 Опубликовано 10 сентября, 2023 · Жалоба 3 hours ago, Arlleex said: Просто меня порой удивляет мнение некоторых товарищей, мол "так никто не пишет", "в C++ все проектируется в других категориях мышления" и ну вообще то так и есть, если речь про старое доброе ООП 3 hours ago, Arlleex said: Это как? Откуда оверхед? У меня на этих макросах оверхед (еще и по ОЗУ) == 0, его просто нет. На любых уровнях оптимизации. у меня каждый пин - это объект, со своим функционалом. Наследуется от абстрактного пина, который используется в других объектах. Мне глубоко до лампочки мизерные экономии на озу, когда его тут вагон и маленькая тележка ) Для хранения объекта нужна память, а чтобы пин дрыгался быстро, объект должен иметь указательно на порт и номер пина порта. Ранее я это не раз расписывал и не хочу уже повторяться. Но мне лично такой подход чертовски удобен. Т.к. в коде нет никакой привязки к железу. Это очень удобно прыгать с камня на камень практически не меняя код. Нынче это особенно актуально, когда один и тот же проект приходится делать сразу под разные камни. Например - STM32 - GD32 - AT32. У меня под каждое семество готовы библиотеки перифирии на плюсах. А макросы практически никогда более не использую. За очень редким исключением. Вот например как использую пины, тут SPI софтовый (аппаратный кстати аналогично) и он общий на все камни, как и SX1261, тоже никак не зависит от железа: class ThreadRadio : public OS::Thread<kRadioStackSize> { public: ThreadRadio() : OS::Thread<kRadioStackSize>("Communication.ThreadRadio") {} private: virtual void initialize() final; virtual void body() final; .... Hardware::Pin<PA1> pinRST; Hardware::Pin<PA2> pinBUSY; Hardware::Pin<PA5> pinSCK; Hardware::Pin<PA7> pinMOSI; Hardware::Pin<PA6> pinMISO; Hardware::Pin<PA4> pinCS1; SoftSPI softSPI {pinSCK, pinMOSI, pinMISO, pinCS1}; SX1261 radio {softSPI, pinBUSY, pinRST}; Подобную схему кстати использую в ардуинах, но мне их подход не очень по душе Макрос тут только Hardware Его достаточно глобально объявить в свойствах проекта, в коде это не фигурирует. И все, проект собирается под камень на другом железе и уже с его библиотеками. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 10 сентября, 2023 Опубликовано 10 сентября, 2023 · Жалоба 12 минут назад, Forger сказал: ну вообще то так и есть, если речь про старое доброе ООП Это все, конечно, хорошо, но, как говорится, не верю Потому что когда пишешь банальный код, типа обычный линейный код с логикой, ООП-шники кричат, что ты все не в стиле ООП делаешь. На вопрос - а где в этот ваш ООП реальный код вставлять, просто повторяют что ты пишешь не так, и гуру пишут классы и всякое там прочее. Такое чувство, что в плюсах код вообще писать не надо. Где написание драйверов? Где написание логики? Где все то, что пишут Си-программисты? Цитата у меня каждый пин Ну вообще я не про пины)) А вообще. У меня эти биты B0...B63 используются очень часто в драйверах периферии и т.д. Вот и стало интересно, что плюсы могут предложить в альтернативу как более правильный и гибкий вариант. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
x893 55 10 сентября, 2023 Опубликовано 10 сентября, 2023 · Жалоба 21 minutes ago, Forger said: Подобную схему кстати использую в ардуинах, но мне их подход не очень по душе В ардуино такой же подход. Названия другие, а смысл тот же. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 10 сентября, 2023 Опубликовано 10 сентября, 2023 · Жалоба 1 hour ago, Arlleex said: У меня эти биты B0...B63 используются очень часто в драйверах периферии и т.д. у меня вся эта аппаратно зависимая "тряхомуть" спрятана глубоко в библиотеках к периферии. Там хороши любые средства, чтобы все работало максимально быстро. В целом использую только h файлы о производителя, все остальное через регистры. Тут главное - продумать интерфейс с этой библиотекой. А что внутри - вторично ) Сразу не рождается правильный и удобный интерфейс, он 'проявляется" от проекта к проекту. Так библиотека постепенно дополняется новым функционалом и постепенно оптимизируется. Сразу это делать абсурд - все равно будет мимо кассы. 1 hour ago, x893 said: В ардуино такой же подход. Так я про это и говорю, просто их вариант с макросами мне как-то не очень. Там вообще смесь голого си и плюсов, причем порой очень причудливая. Речь конечно про сторонние библиотеки . И там нет многозадачности "в стоке". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
x893 55 10 сентября, 2023 Опубликовано 10 сентября, 2023 · Жалоба 30 minutes ago, Forger said: Так я про это и говорю, просто их вариант с макросами мне как-то не очень. Там вообще смесь голого си и плюсов, причем порой очень причудливая. Речь конечно про сторонние библиотеки . И там нет многозадачности "в стоке". Ну там народу много, каждый строчит как хочет. Кухаркам пофиг, что там под "капотом" Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
std 8 10 сентября, 2023 Опубликовано 10 сентября, 2023 (изменено) · Жалоба On 3/16/2023 at 1:16 AM, Arlleex said: Что-то читал я про union-ы в C++ и пришел к выводу, что в комитете дурь очень забористая. Оказывается, нельзя в плюсах репрезентовать битовое представление, как это делалось обычно И выход из ситуации через memcpy(), placement-new [] и иже им подобным костылям с трехэтажным монструозным синтаксисом. Почему Страуструп и Ко просто не взял и не скопировал у Си? Страуструп взял C и добавил к нему фронт-энд прекомпилятор, превращавший си с классами в обычный си код. Он так и назывался, CFront. VC6 (1998) (а также Comeau) имел опцию показать промежуточный этап компиляции C++ в виде C кода. On 3/16/2023 at 2:34 AM, Arlleex said: Он не будет ругаться, а по стандарту вышеуказанный хук слева с union-ом оборачивается UB. О как. Компилятор у меня ARM CLang (keil-овский v6). Он, конечно, код пока что генерит правильно, однако я уже достаточно вкурил, чтобы понять, что плюсоводы такое использование union не одобряют. Одобряют только (и только лишь) хранение разных типов внутри одного кусочка памяти. Обращаться на чтение можно только к элементу, тип которого совпадает с типом элемента на последнюю запись значения в union. Это так называемая установка активного члена union-а. Совсем одурели, в америке своей. Скоре всего это только для смыслового примера. И плюсоводы такое вполне себе мало того что одобряют, это используется в миллионах мест. On 3/16/2023 at 2:47 AM, Arlleex said: Никакие касты (ни static, ни reinterpret) не влияют на UB при доступе к члену union другого типа. Это я тоже почитал(( Получается, по правилам C++ я так сделать не могу. И как тогда могу? Вопросу UB посвещены километры обсуждений. Чтобы понять, надо встать на точку зрения стандартописателей и немного знать о стандарте языка и что именно они пытаются определить своим стандартом. Ключевая мысль: когда описывается стандарт языка, намеренно ничего не предполагают о "платформе" (машине на которой исполняется) и ничего не предполагают о компиляторе. Даже о формате чисел и представлении нуля (null pointer) ранее не делалось никаких предположений (хотя например позже сделаны оговорки о предеставляениях при конверсии). Для указателей например есть предположение только о совпадении == или не-совпадении !=, предположения о монотонном возрастании адресов вообще говоря нет, как нет (или не было на уровне стандарта какого-либо года) даже представления о непрерывности памяти в ряде случаев. Здесь важная оговорка - стандарт C++ постоянно изменяется и некоторые утверждения верны для ранних стандартов и неверны для поздних. Комитет по стандартизации намеренно постарались дать как можно более широкие и абстрактные определения. Они это сделали для того чтобы "натянуть" язык (или что то же самое сделать назвисимым от) всевозможных представлений чисел, любой адресации, и даже вычислений. И так как они придерживаются все время этих правил, они никоим образом не могут (исходя из стандарта, но не из реальности и практики) гарантировать правила преобразования в union, так как это опирается на нечто выходящее за область компетенции стандарта - на модель представления в памяти. И так как они не описывают гарантированное (стандартизованное) поведение это и называется undefined. В смысле undefined в стандарте. Это отсутствие поведения гарантированного на уровне стандарта и только стандарта. Оно же, "отсутствие поведения заданного/описанного стандартом", или "данный стандарт это не описывает и не гарантирует". Внезапно, но и понятие UB описано в стандарте. читаем defns.undefined — behavior for which this document imposes no requirements Расширять эту трактовку на "моя конкретная программа на конкретной платформе обязательно здесь потерпит крах" или гарантированно поведет себя непредсказуемо - неверно. К сожалению, UB само по себе слишком широкое понятие. (UB и так это undefined или unspecified behaviour) Есть неопасный UB, а есть опасный. Что где и как, на что наплевать, а где насторожиться поможет либо опыт, либо статический анализатор кода, либо практические эксперименты на конкретной платформе. Конечным мерилом явлется только практика, в этом смысле оглядываться на каких-то сферических коней в вакууме пишущих о каких-то сферических конях в вакууме с какими-то сферическими запретами в виду сферическо-вакуумного UB... Ну такое... Надо брать и извлекать для себя лучшее. В этом смысл всей этой затеи. Изменено 10 сентября, 2023 пользователем std Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 11 сентября, 2023 Опубликовано 11 сентября, 2023 · Жалоба 13 часов назад, Forger сказал: Мне глубоко до лампочки мизерные экономии на озу, когда его тут вагон и маленькая тележка ) ... тут SPI софтовый Печалька.... На ПК такой подход (возобладавший последнее время) уже привёл к тому, что простейшая программа занимает десятки-сотни МБ ОЗУ. И еле шевелится на CPU, если он не последний, топовый. И уже почти никого не удивляет, что браузер, со всего двумя открытыми вкладками с этим форумом (где почти нет графики и какого-то другого тяжёлого контента), занимает сейчас 550МБ(!) ОЗУ и сжирает 3%(!) времени на почти топовом CPU в режиме просто просмотра страниц! Если бы кому сказали лет 25 назад, что просмотр всего двух не особо больших массивов текста, будет требовать таких конских ресурсов - никто бы не поверил тогда. Теперь же это - норма. 20 часов назад, Arlleex сказал: Теперь я точно знаю, что bit(30) развернется в (1u << 30) и это будет правильно, а bit(60) развернется в (1ull << 60) и при использовании в различных выражениях со смешанными целыми типами данных у меня не будет вылезать куча побочных варнингов из-за неявного приведения типов и т.д. Имхо: Вы излишне усложняете. Можно проще: #define B0 0x00000001ul ... #define B31 0x80000000ul #define B32 (1ull << 32) ... #define B63 (1ull << 63) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 11 сентября, 2023 Опубликовано 11 сентября, 2023 · Жалоба 30 minutes ago, jcxz said: Печалька.... На ПК такой подход (возобладавший последнее время) уже привёл к тому, что простейшая программа занимает десятки-сотни МБ ОЗУ. И еле шевелится на CPU, если он не последний, топовый. Ничего печального в этом не вижу. Это связано не с неким "подходом", а опытом прогеров и требованиями заказчика к срокам и функционалу. А что еле шевелится - это вопрос к программистам или античному компу где все это запускают )) и что прога занимает якобы много озу или много места на диске так это скорее вопрос к владельцам античных дореволюционных компов. У меня лично ногодрыг работает так же как быстро как и на макросах. Но макросы захлямляют код и делают его трудно читаемым и его сложнее отлаживать, компиляторы не очень правильно порой разворачивают макросы. 30 minutes ago, jcxz said: Если бы кому сказали лет 25 назад... если бы кому сказали лет 150 назад что люди будут летать в небе ... если постоянно бодаться за "экономию на спичках", то с таким подходом далеко не уедешь )) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 11 сентября, 2023 Опубликовано 11 сентября, 2023 · Жалоба 2 часа назад, Forger сказал: У меня лично ногодрыг работает так же как быстро как и на макросах. Какой ногодрыг? SPI ногодрыгом? А ничего, что он полностью занимает CPU? 2 часа назад, Forger сказал: Но макросы захлямляют код и делают его трудно читаемым и его сложнее отлаживать, компиляторы не очень правильно порой разворачивают макросы. А у меня скорее вопрос к программистам у которых "компиляторы не очень правильно порой разворачивают макросы". Точнее - к их квалификации. 2 часа назад, Forger сказал: если постоянно бодаться за "экономию на спичках", то с таким подходом далеко не уедешь )) Именно с вашим - не уедешь. Как 25 лет назад надо было ждать пока программа запустится, так и сейчас - почти столько же ждать приходится. Несмотря на то, что скорость железа увеличилась на порядки. PS: Если не давать себе труда напрягать мозги там, где кажется "и так сойдёт", то в конце-концов они совсем закиснут и атрофируются. И когда встретится задача, которая потребует их напрячь, то напрягать будет уже нечего. Никого конкретно не имел в виду, если что.... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 11 сентября, 2023 Опубликовано 11 сентября, 2023 · Жалоба 12 minutes ago, jcxz said: А ничего, что он полностью занимает CPU? Ничего. Т.к. в данном случае обмен ни разу не интенсивный и запас по производительности у камня и так чудовищный. 15 minutes ago, jcxz said: Точнее - к их квалификации. А у меня нет вопросов к квалификации тру поклонников макросов. Это их выбор, их решение. Для меня с-макросы давно пройденный этап, не зацикливаюсь. 13 minutes ago, jcxz said: так и сейчас - почти столько же ждать приходится. У меня компы работают бодро, все. Раньше компы были намного задумчивее. У большинства компов достаточно заменить античный HDD на любой SSD и он сразу оживает, даже полный хлам. 16 minutes ago, jcxz said: И когда встретится задача, которая потребует их напрячь, то напрягать будет уже нечего. Догонять молодежь бессмысленно, видимо и остается только ворчать на сколько она проворна и разводить подобную старческую демагогию )) Я предпочитаю решать проблемы по мере их появления, а не зацикливаться на пустой оптимизации на никому не нужных местах. Мне это уже давно не интересно. Придет мое время и точно так же буду ворчать на молодежь, но надеюсь до этого не дойдет. 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 11 сентября, 2023 Опубликовано 11 сентября, 2023 · Жалоба 16 минут назад, Forger сказал: Догонять молодежь бессмысленно, видимо и остается только ворчать на сколько она проворна и разводить подобную старческую демагогию )) "Проворная" молодёжь, это видимо та, которая не смогла толком освоить даже макросы. Раз у неё "компиляторы не очень правильно порой разворачивают макросы". А догонять мне никого не надо - вся та "проворная молодёжь" дальше ногодрыга как правило не ушла. Что и наблюдается в подавляющем большинстве тем. И для решения элементарной задачи, этой молодёжи нужен не менее чем Cortex-A с тактовой в гигагерц. Так как "не интересно зацикливаться на пустой оптимизации". 16 минут назад, Forger сказал: Я предпочитаю решать проблемы по мере их появления, а не зацикливаться на пустой оптимизации на никому не нужных местах. Мне это уже давно не интересно. Тогда с вами всё ясно. Потому сразу и написал: "печалька". 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 11 сентября, 2023 Опубликовано 11 сентября, 2023 · Жалоба Ладно, коллеги, хватит ссориться)) Я, видимо, зря капнул эту тему, просто нет у меня тут рядом гуру плюсов, чтобы прямо сходу как показали, как рассказали, чтоб я аж офигел и просветлел. Значит, как и раньше, буду потихоньку сам смотреть по ситуации)) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться