-
- Любопытно, вот есть класс UART, в нем обработчик прерывания void
i();. В программе создаем два объекта UART u1, u2; Как привязать
u1.i() и u2.i() к разным физическим прерываниям, не используя
Сишных прокладок? - AlexBi(03.10.2022 08:22)
- Никак. Т.к. ядро процессора/контроллера не умеет одновременно указатель на объект (this) и адрес/смещение функции вычислить. - Costic(03.10.2022 16:50)
- Как вариант. Переносите таблицу прерываний в ОЗУ. В конструктор класса UART передаёте его номер и создаёте объекты UART u1(1), u2(2); Конструктор класса UART устанавливает свой обработчкик в таблицу векторов прерываний при создании объекта. Можно и другие варианты придумать, была бы необходимость. Но прокладка - самое простое. Мир от её использования не перевернётся. - VladislavS.(03.10.2022 10:06)
- Так элементарно. Обработчик прерывания - обычная Си'шная функция
extern "C" { void Uart1Int(void) { u1.i(); } void Uart2Int(void) {
u2.i(); } } - =AlexD=(03.10.2022 08:28)
- Это и есть сишные прокладки, нет? КМК, значительная часть проблем
плюсов в том, что плюсовая публика излишне идеологизирована: "Нет
сишным прокладкам! Мы тут плюсы или где?" - SciFi(03.10.2022 08:35)
- Это ваши тараканы какие-то. Почему вы боитесь "прокладок"? Они даже
накладных расходов не несут. Смотрите примеры: VladislavS.(1068 знак., 03.10.2022 08:54)
- static не годится, т.к. для u1 и u2 он будет одинаковый. Сишные
прокладки не удобны, т.к. u1 может быть внутри другого объекта, а
тот внутри еще чего-то, либо вообще создаваться динамически. Вся
красота теряется. - AlexBi(03.10.2022 09:12)
- Бесконечное вложение классов дуг в друга - это не "красиво" - =AlexD=(03.10.2022 09:38)
- Не класса в класс, а объекта в объект или объекта в класс. - VladislavS.(03.10.2022 09:43)
- Чуть ниже пример с USB. Там обработчик статик, но вызвает методы разных объектов в зависимости от того какой из портов обрабатывает. - VladislavS.(03.10.2022 09:32)
- Задачи бывают разные. Где-то static подойдёт, где-то метод динамически созданного объекта (в эмбедде? правда, правда?). - VladislavS.(03.10.2022 09:17)
- Бесконечное вложение классов дуг в друга - это не "красиво" - =AlexD=(03.10.2022 09:38)
- Это прекрасно. Только непонятно, зачем вообще нужен класс, когда
там всего две функции. Лишняя сущность же. - SciFi(03.10.2022 08:56)
- Или вот пример обработчиков с шаблонным классом. В контроллере два
USB, класс один, объектов два, обработчиков прерываний два. VladislavS.(1 знак., 03.10.2022 09:33, картинка)
- А я бы привёл другой пример. Да, с лишним сгенерённым кодом, но
может быть он понятнее "бедуинам"? Costic(541 знак., 03.10.2022 17:09, ссылка)
- Зачем же в микроконтроллере объекты динамически создавать? VladislavS.(1 знак., 03.10.2022 17:37, ссылка)
- В моём примере демонстрировались виртуальные функции. Подправил так: Costic(1 знак., 03.10.2022 18:49, ссылка)
- Зачем же в микроконтроллере объекты динамически создавать? VladislavS.(1 знак., 03.10.2022 17:37, ссылка)
- вот, похоже на ответ. То есть из plain C можно обращаться уже к C++
выходит? - Dingo(03.10.2022 10:09)
- Без некоторого рукоблудства нет. В С++ есть механизм перегрузки
функций. Чтобы компилятор различал разные кандидаты на перегрузку
при компиляции к именам функций добавляются префиксы, зависящие от
аргументов. В объектных файлах эти имена могут быть очень
причудливыми. Например, SysTick_Handler() превратится в
_Z15SysTick_Handlerv. Если функции с аргументами, то имя сильно
разрастается. Функцию с таким именем из С-кода не вызвать. Для того
чтобы отключить этот механизм VladislavS.(160 знак., 03.10.2022 10:28 - 10:41)
- Это позволяет из ASM, и любого другого языка вызвать С++ функцию,
если он поддерживает Си'шное соглашение о вызовах. - =AlexD=(03.10.2022 10:31)
- В общем случае именно так. - VladislavS.(03.10.2022 10:33)
- Это позволяет из ASM, и любого другого языка вызвать С++ функцию,
если он поддерживает Си'шное соглашение о вызовах. - =AlexD=(03.10.2022 10:31)
- Это С++, просто указание компилятору, что вот к этому конкретному имени функции применяется asm трансляция имён в стиле Си, а не С++. - =AlexD=(03.10.2022 10:24)
- Без некоторого рукоблудства нет. В С++ есть механизм перегрузки
функций. Чтобы компилятор различал разные кандидаты на перегрузку
при компиляции к именам функций добавляются префиксы, зависящие от
аргументов. В объектных файлах эти имена могут быть очень
причудливыми. Например, SysTick_Handler() превратится в
_Z15SysTick_Handlerv. Если функции с аргументами, то имя сильно
разрастается. Функцию с таким именем из С-кода не вызвать. Для того
чтобы отключить этот механизм VladislavS.(160 знак., 03.10.2022 10:28 - 10:41)
- Кто-нибудь рискнёт сказать, что тут прокладки и это "недостаточно
С++"? Для реализации подобного на С две почти одинаковые функции
придётся писать? Только не надо про макросы... - VladislavS.(03.10.2022 09:52)
- Почему же не надо про макросы? Шаблоны это грубо замена макросам.
Предложенный пример спокойно реализуется через склейку. Только вся
натянутость шаблонных решений (плевать шаблоны плюсов или макросы)
не помогает навигации/отладке. Не буду говорить плохо о плюсах, а
хорошо не могу - у меня на них идиосинкразия. НО пример,
КМК,подобран именно идеологический и выбран вариант получения
экземпляров метода в зависимости от параметра с прицелом на
не-рантайм. В Сях не-рантайм - это Vit(263 знак., 03.10.2022 11:33)
- Макросы не имеют области видимости. Вот в виндузовых хедерах
какой-то альтернативно одарённый перец догадался определить макросы
min и max ловеркейсом, и привет - вы пишете void set_limits(int
min, int max), и препроцессор вам вместо параметров функции
подставляет самизнаетечто. С шаблонами такого не происходит. - йцyкeн(03.10.2022 13:19)
- Криворукость и возможности:) - это всегда расширяет кругозор:))) Я,
например, отношусь к шаблонам как к костылям, которые лишь
позволили говорить, что "можно без макросов". Для меня они ещё
более отдаляют С++ от удобоваримости Vit(1 знак., 03.10.2022 13:55, картинка)
- Просто вы не умеете их готовить. Для меня китайский - сущая
тарабарщина, а 1.5 млрд китайцев на нём говорят и не парятся. - VladislavS.(03.10.2022 14:49)
- Так и не собираюсь. Хотя иногда приходится копаться в. Считаю плюсы
рудиментарным звеном:) между Си и Си-Шарпом - Vit(03.10.2022 16:06)
- C# в микроконтроллер? Оригинально. Ж) - VladislavS.(03.10.2022 16:45)
- Так и не собираюсь. Хотя иногда приходится копаться в. Считаю плюсы
рудиментарным звеном:) между Си и Си-Шарпом - Vit(03.10.2022 16:06)
- Просто вы не умеете их готовить. Для меня китайский - сущая
тарабарщина, а 1.5 млрд китайцев на нём говорят и не парятся. - VladislavS.(03.10.2022 14:49)
- Криворукость и возможности:) - это всегда расширяет кругозор:))) Я,
например, отношусь к шаблонам как к костылям, которые лишь
позволили говорить, что "можно без макросов". Для меня они ещё
более отдаляют С++ от удобоваримости Vit(1 знак., 03.10.2022 13:55, картинка)
- Само собой, пример подобран. Какой смысл показывать примеры, где не будет разницы? В целом вы правильно понимаете суть происходящего, но сильно недооцениваете силу шаблонов и constexpr. - VladislavS.(03.10.2022 11:48)
- Макросы не имеют области видимости. Вот в виндузовых хедерах
какой-то альтернативно одарённый перец догадался определить макросы
min и max ловеркейсом, и привет - вы пишете void set_limits(int
min, int max), и препроцессор вам вместо параметров функции
подставляет самизнаетечто. С шаблонами такого не происходит. - йцyкeн(03.10.2022 13:19)
- На С писать придется примерно так же, как на С++, те же две
функции, или одну, напичканную if-ами. Или я чего-то не понимаю ... AlexBi(1 знак., 03.10.2022 10:29, картинка)
- if будет выполняться в рантайме при каждом вызове прерывания. От if
constexpr останется только USB_FS_OBJECT.Enumerate_Reset() в
прерывании USB_FS, и USB_HS_OBJECT.Enumerate_Reset() в прерывании
USB_HS на этапе компиляции. Никаких if в рантайме не будет. - VladislavS.(03.10.2022 10:42)
- От обычного if, применённого к константе, в коде тоже ничего не
остаётся. йцyкeн(1 знак., 03.10.2022 13:55, ссылка)
- А ещё c простым if обе ветки условия должны корректно компилироваться. С if constexpr они должны быть всего лишь синтаксически правильно составлены. Накидал пример: Под if константа. VladislavS.(8 знак., 03.10.2022 16:11, ссылка)
- Зависит от оптимизации и от того находится ли код в другой единице
трансляции. VladislavS.(8 знак., 03.10.2022 14:23, ссылка)
- Ну разумеется. Вы сделали x не параметром шаблона, а параметром
функции. Теперь это не константа. - йцyкeн(03.10.2022 14:32)
- Как же не константа? Включите -O1 и "о чудо" случится. Самая
настоящая константа. VladislavS.(214 знак., 03.10.2022 14:45)
- Нет. Для функции plusminus x не является константой, поэтому в
ассемблерном тексте проверка условия сохранилась в виде инструкции
cmove. А вот в местах вызова фактические параметры являются
константами, и там оптимизатор заменил вызовы plusminus
результатами этих вызовов. - йцyкeн(03.10.2022 14:47)
- Вот мы и вышли на разный уровень - либо это константа по стандарту языка, либо оптимизатор так решил. Поэтому, где рассчитываем иметь константу пишем if constexpr, чтобы муха не проскочила. Не всегда так просто определить "на глаз" константность данных, пусть этим компилятор занимается. - VladislavS.(03.10.2022 14:53)
- Нет. Для функции plusminus x не является константой, поэтому в
ассемблерном тексте проверка условия сохранилась в виде инструкции
cmove. А вот в местах вызова фактические параметры являются
константами, и там оптимизатор заменил вызовы plusminus
результатами этих вызовов. - йцyкeн(03.10.2022 14:47)
- Как же не константа? Включите -O1 и "о чудо" случится. Самая
настоящая константа. VladislavS.(214 знак., 03.10.2022 14:45)
- Ну разумеется. Вы сделали x не параметром шаблона, а параметром
функции. Теперь это не константа. - йцyкeн(03.10.2022 14:32)
- Чем это будет отличаться от вызова
Enumerate_Reset(&USB_FS_OBJECT) и
Enumerate_Reset(&USB_HS_OBJECT) в соответствующих обработчиках
прерываний, если все писать в С-стиле? - AlexBi(03.10.2022 10:46)
- Тем что метод Enumerate_Reset должен уметь с этим
&USB_FS_OBJECT что-то делать. Это дополнительный код. А выбор
между вызовом Enumerate_Reset(&USB_FS_OBJECT) или
Enumerate_Reset(&USB_HS_OBJECT) в рантайме или макросом? - VladislavS.(03.10.2022 10:54)
- Разве внутри USB_FS_OBJECT.Enumerate_Reset() не делается что-то с
USB_FS_OBJECT? Или смущает что вместо x придется писать
arg->x, или вместо foo() придется писать arg->foo(arg)? AlexBi(237 знак., 03.10.2022 11:13, картинка)
- C++ программиста вообще ничего не смущает, а уж объём текста и
подавно :) А вот во что это в кончном счёте скомпилируется очень
даже. Во-первых, передать аргумент в Enumerate_Reset не бесплатно.
Во-вторых внутри придётся много проверок аргумента делать, чтобы
выбирать с каким из двух USB-портов оперировать. В-третьих,
Enumerate_Reset static inline и его вызова вообще не будет. Что-то
оптимизатор вытянет, но далеко не всё. Код будет медленней, а это
прерывание. Ну и VladislavS.(45 знак., 03.10.2022 11:29)
- Если так переживать за скорость, что учитывать количество
передаваемых аргументов, то в С++ придется делать изрядное
количество static, т.к. любой вызов не static метода неявно требует
передачи одного параметра, а в программах очень часто встречается
единственный объект класса. Не уверен, что оптимизатор способен
обнаружить это самостоятельно и сделать код как для static, хотя
формально препятствий нет. AlexBi(261 знак., 03.10.2022 11:43)
- inline IRQHandler улыбнуло. А куда его можно встроить? Впрочем,
inline это такое слово-паразит в С. Пиши не пиши - ничего не
изменится. В С++ у него хоть другие применения есть. - VladislavS.(03.10.2022 12:27)
- Встраивать я предполагал туда AlexBi(244 знак., 03.10.2022 12:39, картинка)
- Мне кажется, польза inline незаслуженно преувеличена. Он не нужен.
Сэкономить пару тактов? Это бывает нужно два раза в год, и inline
там будет нужен в последнюю очередь. Следовательно, если погромиздъ
применяет inline чаще, чем 2 раза в год, он демонстрирует
неадекватную оценку реальных требований к софту. - SciFi(03.10.2022 12:45)
- На мелких контроллерах типа ПИК это экономия стека, который весьма
мелкий. Но программу при этом удобнее писать в виде отдельных
функций, вызывающих друг друга. Приходится следить за глубиной
вложенности. AlexBi(115 знак., 03.10.2022 12:49)
- Так большинство аргументов обычно и разбивается об скалу "и это всё
ради пары тактов?". А пара тактов тут, пара тактов там, тем более
что это всё делает компилятор и уже набегает разница. - VladislavS.(03.10.2022 12:59)
- Всё так. Только на самом деле не набегает :-) - SciFi(03.10.2022 13:02)
- Есть опыт или с потолка? - VladislavS.(03.10.2022 13:09)
- Опыт есть. И да, "набегает" - это с потолка :-) - SciFi(03.10.2022 13:37)
- Получается моё кун-фу сильнее твоего :) VladislavS.(48 знак., 03.10.2022 13:55, youtube)
- Опыт есть. И да, "набегает" - это с потолка :-) - SciFi(03.10.2022 13:37)
- Есть опыт или с потолка? - VladislavS.(03.10.2022 13:09)
- Всё так. Только на самом деле не набегает :-) - SciFi(03.10.2022 13:02)
- Так большинство аргументов обычно и разбивается об скалу "и это всё
ради пары тактов?". А пара тактов тут, пара тактов там, тем более
что это всё делает компилятор и уже набегает разница. - VladislavS.(03.10.2022 12:59)
- На мелких контроллерах типа ПИК это экономия стека, который весьма
мелкий. Но программу при этом удобнее писать в виде отдельных
функций, вызывающих друг друга. Приходится следить за глубиной
вложенности. AlexBi(115 знак., 03.10.2022 12:49)
- Мне кажется, польза inline незаслуженно преувеличена. Он не нужен.
Сэкономить пару тактов? Это бывает нужно два раза в год, и inline
там будет нужен в последнюю очередь. Следовательно, если погромиздъ
применяет inline чаще, чем 2 раза в год, он демонстрирует
неадекватную оценку реальных требований к софту. - SciFi(03.10.2022 12:45)
- Встраивать я предполагал туда AlexBi(244 знак., 03.10.2022 12:39, картинка)
- В случае с С++ есть возможность писать код методов в заголовочном
файле. Тогда весь код будет в одной единице трансляции и
возможности оптимизации сильно выше. Статик или не статик тогда на
оптимизацию не сильно влияет. Пример на эту тему: VladislavS.(248 знак., 03.10.2022 12:18, картинка)
- Даже если весь код под рукой, компилятор отказывается инлайнить
единственный вызов функции. Правда это все С-компиляторы, с
которыми я имел дело, как у С++ не знаю. - AlexBi(03.10.2022 12:44)
- Да дадно, а если попросить? :) VladislavS.(1 знак., 03.10.2022 13:08, картинка)
- Даже если весь код под рукой, компилятор отказывается инлайнить
единственный вызов функции. Правда это все С-компиляторы, с
которыми я имел дело, как у С++ не знаю. - AlexBi(03.10.2022 12:44)
- Мне тоже кажется жутко неудобным, что нельзя весь класс объявить статическим, не по области видимости, а по методам. - =AlexD=(03.10.2022 11:49)
- inline IRQHandler улыбнуло. А куда его можно встроить? Впрочем,
inline это такое слово-паразит в С. Пиши не пиши - ничего не
изменится. В С++ у него хоть другие применения есть. - VladislavS.(03.10.2022 12:27)
- Если так переживать за скорость, что учитывать количество
передаваемых аргументов, то в С++ придется делать изрядное
количество static, т.к. любой вызов не static метода неявно требует
передачи одного параметра, а в программах очень часто встречается
единственный объект класса. Не уверен, что оптимизатор способен
обнаружить это самостоятельно и сделать код как для static, хотя
формально препятствий нет. AlexBi(261 знак., 03.10.2022 11:43)
- C++ программиста вообще ничего не смущает, а уж объём текста и
подавно :) А вот во что это в кончном счёте скомпилируется очень
даже. Во-первых, передать аргумент в Enumerate_Reset не бесплатно.
Во-вторых внутри придётся много проверок аргумента делать, чтобы
выбирать с каким из двух USB-портов оперировать. В-третьих,
Enumerate_Reset static inline и его вызова вообще не будет. Что-то
оптимизатор вытянет, но далеко не всё. Код будет медленней, а это
прерывание. Ну и VladislavS.(45 знак., 03.10.2022 11:29)
- Разве внутри USB_FS_OBJECT.Enumerate_Reset() не делается что-то с
USB_FS_OBJECT? Или смущает что вместо x придется писать
arg->x, или вместо foo() придется писать arg->foo(arg)? AlexBi(237 знак., 03.10.2022 11:13, картинка)
- Тем что метод Enumerate_Reset должен уметь с этим
&USB_FS_OBJECT что-то делать. Это дополнительный код. А выбор
между вызовом Enumerate_Reset(&USB_FS_OBJECT) или
Enumerate_Reset(&USB_HS_OBJECT) в рантайме или макросом? - VladislavS.(03.10.2022 10:54)
- От обычного if, применённого к константе, в коде тоже ничего не
остаётся. йцyкeн(1 знак., 03.10.2022 13:55, ссылка)
- if будет выполняться в рантайме при каждом вызове прерывания. От if
constexpr останется только USB_FS_OBJECT.Enumerate_Reset() в
прерывании USB_FS, и USB_HS_OBJECT.Enumerate_Reset() в прерывании
USB_HS на этапе компиляции. Никаких if в рантайме не будет. - VladislavS.(03.10.2022 10:42)
- Почему же не надо про макросы? Шаблоны это грубо замена макросам.
Предложенный пример спокойно реализуется через склейку. Только вся
натянутость шаблонных решений (плевать шаблоны плюсов или макросы)
не помогает навигации/отладке. Не буду говорить плохо о плюсах, а
хорошо не могу - у меня на них идиосинкразия. НО пример,
КМК,подобран именно идеологический и выбран вариант получения
экземпляров метода в зависимости от параметра с прицелом на
не-рантайм. В Сях не-рантайм - это Vit(263 знак., 03.10.2022 11:33)
- А я бы привёл другой пример. Да, с лишним сгенерённым кодом, но
может быть он понятнее "бедуинам"? Costic(541 знак., 03.10.2022 17:09, ссылка)
- Чтобы не писать в каждой функции аргументом указатель на структуру с данными. Экономия пальцекликов ;-) Но вообще то прикольно, когда интеллектуальный помощник редактора сам вываливает тебе список методов после точки. Можно не морщить моск и не заглядывать в хедер. Удобненько. - =AlexD=(03.10.2022 09:03)
- Что значит две функции? Это же пример. Класс может быть сколь угодно сложным. Один из методов - обработчик прерываний. Вот вам класс с тремя навороченными методами, один из которых обработчик прерываний. VladislavS.(155 знак., 03.10.2022 09:00)
- Или вот пример обработчиков с шаблонным классом. В контроллере два
USB, класс один, объектов два, обработчиков прерываний два. VladislavS.(1 знак., 03.10.2022 09:33, картинка)
- static не годится, т.к. для u1 и u2 он будет одинаковый. Сишные
прокладки не удобны, т.к. u1 может быть внутри другого объекта, а
тот внутри еще чего-то, либо вообще создаваться динамически. Вся
красота теряется. - AlexBi(03.10.2022 09:12)
- Плюсы в отличии от Си не универсальны, увы. Это совершенно очевидно любому, кто с ними хоть немного поработал. И отсутствие стандарта (хотя бы _дефакто) на именование функций в ASM выхлопе - одна из проблем. Можно извернуться, забиндить метод с аргументом и как-то прописать указатель в таблицу векторов, но это по сути будет ровно то-же самое, что я написал, только через жопу. - =AlexD=(03.10.2022 08:45)
- Это ваши тараканы какие-то. Почему вы боитесь "прокладок"? Они даже
накладных расходов не несут. Смотрите примеры: VladislavS.(1068 знак., 03.10.2022 08:54)
- Это и есть сишные прокладки, нет? КМК, значительная часть проблем
плюсов в том, что плюсовая публика излишне идеологизирована: "Нет
сишным прокладкам! Мы тут плюсы или где?" - SciFi(03.10.2022 08:35)
- Любопытно, вот есть класс UART, в нем обработчик прерывания void
i();. В программе создаем два объекта UART u1, u2; Как привязать
u1.i() и u2.i() к разным физическим прерываниям, не используя
Сишных прокладок? - AlexBi(03.10.2022 08:22)