Quasar 20 7 января Опубликовано 7 января · Жалоба В 05.01.2024 в 05:59, dxp сказал: всякие интересные штуки типа замыканий (closure -- захват контекста) А я вот как-то не соображу. В Java замыкания и лямбды я часто использую, для отложенного выполнения кода (например, чтобы не в ГУИ потоке его выполнять). Ну то есть, создается лямбда, ставится в очередь на исполнение и потом, когда-то там исполняется... Но в C++ просто создать лямбду в области видимости, запихать ее в очередь на исполнение, а потом уйти из области видимости не получится? Лямбда локальная переменная и она исчезнет как и все локальные переменные. Сходу погуглив, нашел лишь примеры, когда после создания лямбды и исполнения ее в другом потоке, из зоны видимости не выходят. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 56 7 января Опубликовано 7 января · Жалоба 13 часов назад, Quasar сказал: Но в C++ просто создать лямбду в области видимости, запихать ее в очередь на исполнение, а потом уйти из области видимости не получится? Лямбда локальная переменная и она исчезнет как и все локальные переменные. Сходу погуглив, нашел лишь примеры, когда после создания лямбды и исполнения ее в другом потоке, из зоны видимости не выходят. Ну, если делаете захват по значению, то проблем вроде и нет. А по ссылке -- да, тут так просто в С++ нельзя делать, нужно следить за тем, чтобы переменная, захваченная по ссылке, существовала в момент обращения к ссылке. Это обычное правило C/С++, когда не нужно передавать во внешний контекст вызываемой функции указатели на локальные объекты, т.к. после выхода из функции эти объекты уже не существуют. UPD. Перечитал цитату. Выше ответил не на этот вопрос. Но принцип там тот же. Да, лямбда -- это такой же объект, как и другие, подчиняется общим правилам. Поэтому если это локальный объект внутри, например, функции, то передавать указатель (или ссылку) на него за пределы функции нельзя. Но вполне можно, к примеру, вернуть такой объект из функции по значению. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 166 11 января Опубликовано 11 января · Жалоба Позвольте еще немного подушнить😃 В 05.01.2024 в 08:59, dxp сказал: Перечислимый тип в С -- это и не тип никакой, а просто способ создавать именованные литералы. Ну почему. Изначально планировался именно как тип. Целый перечисляемый тип. И в стандарте описан как тип. Цитата А если пара enum'ов, описывающих состояния конечного автомата, в обоих есть по смыслу одинаковое состояние WAIT, то вот он и конфликт имён сразу же. :: от нужного enum? Или Вы всегда их безымянными делаете? Тогда да, никак. Но у меня привычка enum eName { ... };🙂 Я стараюсь enum (и даже enum class) держать близко к месту использования, чтобы все эти имена не торчали в окружающем пространстве имен. А пространство имен модуля ограничиваю namespace-ом этого модуля (модуль == некая единица трансляции или их группа). Удобно, вроде как. Насчет предикатов, функторов, лямбд: насколько я понял, их ценность кроется, в основном, при работе со стандартной библиотекой. А вот constexpr действительно, хорошая штука. Глубина "прохода" компилятора в этих выражениях выше, чем у обычных const в Си. Поэтому даже на малых уровнях оптимизации (не помню как насчет -O0) целый алгоритм с вызовами функций, циклами, условными выражениями и т.д., сворачивается в финальную константу и в финале там 2 ассемблерные инструкции. Единственное, какого-то вменяемого полного описания constexpr-выражений и функций, constexpr if() найти не просто, т.к. между C++11 и C++17 с этими constexpr что-то произошло (че то там передумали в стандарте), поэтому в интернетах натыкаюсь на противоречивые статьи. Например: почему следующая строчка не вычисляется в compile-time? void func() { u32 constexpr i = ... ; // ... тут может быть некое выражение, где над числом издеваются (<<, >>, |, ~, & и т.д.), но это точно константа } Стоит добавить static перед объявлением, как выражение полностью становится compile-time. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 133 11 января Опубликовано 11 января · Жалоба 12 минут назад, Arlleex сказал: Но у меня привычка enum eName { ... }; А пофиг. Только enum class ограничивает область видимости имен. 14 минут назад, Arlleex сказал: Изначально планировался именно как тип. Целый перечисляемый тип. И в стандарте описан как тип. Но неявное преобразование к int и из int, плюс хранение в ячейке памяти такого же размера, как int свело все планы на нет. Получили "птицу, которая выглядит как утка, плавает как утка и крякает как утка", но назвали ее, почему-то, не уткой. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladislavS 39 11 января Опубликовано 11 января · Жалоба 1 час назад, Arlleex сказал: Насчет предикатов, функторов, лямбд: насколько я понял, их ценность кроется, в основном, при работе со стандартной библиотекой. И при написании своих библиотек. В рядовом коде они, действительно, выглядят не очень уместно. Но когда с ними на ты, то так и подмывает применить. 1 час назад, Arlleex сказал: почему следующая строчка не вычисляется в compile-time? В смысле? auto constexpr X = 100; auto Y = 100; auto func() { int constexpr i = X<<2; // Компайлтайм, Ok int constexpr I = Y<<2; // Рантайм, ошибка } 1 час назад, Arlleex сказал: Стоит добавить static перед объявлением, как выражение полностью становится compile-time. Ни в коем случае, это сделает локальную переменную фактически глобальной для данной функции, но она всё так же должна быть инициализирована вычисленным на этапе компиляции значением. 1 час назад, Arlleex сказал: не помню как насчет -O0 и это не зависит от оптимизации. При любой оптимизации должно быть вычислено на этапе компиляции. 1 час назад, Arlleex сказал: Единственное, какого-то вменяемого полного описания constexpr-выражений и функций, constexpr if() найти не просто Да вроде всё просто: 1. constexpr переменные (читай константы). Они всегда должны быть инициализированы значением вычисленным на этапе компиляции. 2. constexpr функции. Они могут работать как в компайлтайме, так и в рантайме. В первом случае (когда все условия сложились) их значения можно использовать там где подразумевается константа этапа компиляции: параметры шаблонов, инициализация constexpr переменных, if constexpr()... Если значение нельзя в компайлтайме вычислить, то работает как обычная функция в рантайме. В С++20 появилось более жёсткое consteval, которое не пускает функцию в рантайм. 3. if constexpr() Тут всё просто. Выражение "под условием" должно быть вычислено на этапе компиляции. 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
amaora 23 11 января Опубликовано 11 января · Жалоба А кто-нибудь здесь пишет event-driven с использованием средств C++? Лямбды и замыкания напрашиваются, чтобы ими записывать цепочки callback функций с сохранением контекста. Иногда интересуюсь, но попробовать времени не хватает. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 166 11 января Опубликовано 11 января · Жалоба 1 час назад, Сергей Борщ сказал: Получили "птицу, которая выглядит как утка, плавает как утка и крякает как утка", но назвали ее, почему-то, не уткой. Ну, наверное. 44 минуты назад, VladislavS сказал: Ни в коем случае, это сделает локальную переменную фактически глобальной для данной функции, но она всё так же должна быть инициализирована вычисленным на этапе компиляции значением. Ввел в заблуждение, извиняюсь. Сейчас открыл проект, еще раз глянул, в чем был вопрос, а он и не в constexpr на самом то деле. inline void initGPIO() { cpu_alloc_critical_section_context(csc); cpu_entry_critical_section(csc); u32 constexpr moderCLSBSet = 1u << GPIO_MODER_MODER10_Pos | 1u << GPIO_MODER_MODER12_Pos; upd_bit(GPIOC->MODER, rst(0x3 * moderCLSBSet), set(0x2 * moderCLSBSet), inv(0)); __DSB(); cpu_leave_critical_section(csc); } Спойлер 0x08000634 B085 SUB sp,sp,#0x14 122: cpu_entry_critical_section(csc); 123: 0x08000636 E7FF B 0x08000638 401: __ASM volatile ("MRS %0, primask" : "=r" (result) ); 0x08000638 F3EF8010 MRS r0,PRIMASK 0x0800063C 9002 STR r0,[sp,#0x08] 402: return(result); 0x0800063E 9802 LDR r0,[sp,#0x08] 0x08000640 9001 STR r0,[sp,#0x04] 0x08000642 F3EF8010 MRS r0,PRIMASK 0x08000646 B672 CPSID I 0x08000648 9003 STR r0,[sp,#0x0C] 0x0800064A E7FF B 0x0800064C 0x0800064C F04F7088 MOV r0,#0x1100000 124: u32 constexpr moderCLSBSet = 1u << GPIO_MODER_MODER10_Pos | 125: 1u << GPIO_MODER_MODER12_Pos; 126: 0x08000650 9000 STR r0,[sp,#0x00] 0x08000652 F6400000 MOVW r0,#0x800 0x08000656 F2C40002 MOVT r0,#0x4002 127: upd_bit(GPIOC->MODER, rst(0x3 * moderCLSBSet), set(0x2 * moderCLSBSet), inv(0)); 128: 0x0800065A 6801 LDR r1,[r0,#0x00] 0x0800065C F021714C BIC r1,r1,#0x3300000 0x08000660 F1017108 ADD r1,r1,#0x2200000 0x08000664 6001 STR r1,[r0,#0x00] 129: __DSB(); 130: 0x08000666 F3BF8F4F DSB.W 131: cpu_leave_critical_section(csc); 0x0800066A 9801 LDR r0,[sp,#0x04] 0x0800066C 9004 STR r0,[sp,#0x10] 429: __ASM volatile ("MSR primask, %0" : : "r" (priMask) : "memory"); 0x0800066E 9804 LDR r0,[sp,#0x10] 429: __ASM volatile ("MSR primask, %0" : : "r" (priMask) : "memory"); 0x08000670 F3808810 MSR PRIMASK,r0 132: } 133: 0x08000674 B005 ADD sp,sp,#0x14 0x08000676 4770 BX lr Видна пара MOV 0x1100000 + последующий STR в стек. Как только добавляю static, эти две инструкции пропадают. Поведение логично. Оно и с обычным const так. Видимо, я когда-то в отладке хотел избавиться от этих лишних запихиваний в стек на -O0. Не нашел другого способа, как добавить static, map-файл говорит, что линкер после линковки удалил эти 4 байта. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 166 11 января Опубликовано 11 января · Жалоба 48 минут назад, VladislavS сказал: Ни в коем случае, это сделает локальную переменную фактически глобальной для данной функции, но она всё так же должна быть инициализирована вычисленным на этапе компиляции значением. Опять же - это ведь не переменная, а константа. static const или static constexpr - это объявление не переменной, а константы. Видимость ограничена блоком (функцией), время жизни - глобальное, супер. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladislavS 39 11 января Опубликовано 11 января · Жалоба 22 минуты назад, amaora сказал: А кто-нибудь здесь пишет Не знаю это ли вы имеете в виду. Вот у меня в одной из библиотек обработчик прерываний USB. В нём IRQHandlers это список типов. Для каждого элемента списка выполняется лямбда. А сам список зависит от реализуемого класса. Например, для CDC обработчики двух конечных точек. 3 минуты назад, Arlleex сказал: Опять же - это ведь не переменная, а константа. Вообще-то переменная. Изменять нельзя, правда. :))) 4 минуты назад, Arlleex сказал: Видимость ограничена блоком (функцией), время жизни - глобальное, супер. Это и в православном С так было со статическими локальными переменными. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
amaora 23 11 января Опубликовано 11 января (изменено) · Жалоба 3 hours ago, VladislavS said: Не знаю это ли вы имеете в виду. Вот у меня в одной из библиотек обработчик прерываний USB. В нём IRQHandlers это список типов. Для каждого элемента списка выполняется лямбда. Ну здесь я вижу передачу тела цикла в свой foreach который видимо работает в compile-time. Не об этом спрашивал. Для примера, если бы при обработке прерывания возникла необходимость подождать некоторого события (например сброс BUSY флажка), а после сделать ещё какие-то действия. Вот эти действия можно записать лямбдой, захватить в неё необходимый контекст и передать планировщику в качестве обработчика события "BUSY=0". Код будет похож на линейный, как если бы ждали флажок в цикле. Интересна имитация блокирующих функций в таком стиле, подписка на событие и продолжение работы в обработчике. Как бы тогда мог выглядеть какой-нибудь сильно разветвленный код с множеством вложенных вызовов? Например, реализация printf, которая на нижнем уровне вызывает putc. Не будут ли слишком велики накладные расходы на передачу контекста? Как достаточно красиво делать длинные цепочки обработчиков? Примитивный псевдокод. Spoiler void putc(char x, ehtype eh) { uart_queue.put(x); uart_waiting.put(eh); } ... void UART_ISR() { ... while (uart_queue.space() > 0 && uart_waiting.len() > 0) { auto eh = uart_waiting.get(); eh(); } } ... putc('0' + i, [=] () { i++; putc('0' + i, [=] () { ... }); }); Изменено 11 января пользователем amaora Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
razrab83 21 17 января Опубликовано 17 января · Жалоба уважаемые плюсоводы, подскажите... файл *.cpp, код такой int *array[] = { new int(1), 0 }; объявлен и определён массив указателей вне тела функции. с компилятором arm-none-eabi-g++ -mcpu=cortex-m4 -std=gnu++17 работает. с IAR ANSI C/C++ Compiler V9.40.1.364/W64 for ARM (--cpu=Cortex-M4, --c++, с++17) зависает до майна на операторе new. На одном и том же МК. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 133 17 января Опубликовано 17 января · Жалоба Неужели нет внутрисхемного отладчика, чтобы запустить под ним программу и посмотреть, куда ее унесло? Вангую, что не выделена память под кучу, new int(1) не смог зарезервировать память и свалился в заглушку с бесконечным циклом. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladislavS 39 17 января Опубликовано 17 января · Жалоба Да вроде всё работает. Настройки по умолчанию. Память под кучу выделена? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
razrab83 21 18 января Опубликовано 18 января · Жалоба Локализовал проблему. Память под хип выделена, но во внешней SDRAM, которая инитится в main. Всем спасибо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
EdgeAligned 79 18 января Опубликовано 18 января · Жалоба Во внешней SDRAM хранить одиночные переменные или малые объемы данных - неэффективно. SDRAM имеет много издержек на одиночные обращения - выбор строки, выбор столбца, задержки CAS/RAS, чтение/запись. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться