Перейти к содержанию
    

dxp

Свой
  • Постов

    4 564
  • Зарегистрирован

  • Посещение

  • Победитель дней

    14

Весь контент dxp


  1. Если хотите скомпилировать пакет вместе с файлом, который его использует, то исходный код пакета надо включить, например, с помощью `include. Если файл с пакетом находится в другой директории,, нежели исходный, то компилятор может его не найти, тогда нужно компилятору указать пути поиска (+incdir+...). Пакеты до компиляции проекта можно откомпилировать в отдельную библиотеку, которую подключать к vopt как обычно с ключом -L. Тогда ничего включать с помощью `include уже не надо, достаточно только import.
  2. Offtopic. @mse, подскажите, пожалуйста, что за шрифт вы используете тут?
  3. Для ночных бекапов вполне работает cron + rsync.
  4. Ну, если делаете захват по значению, то проблем вроде и нет. А по ссылке -- да, тут так просто в С++ нельзя делать, нужно следить за тем, чтобы переменная, захваченная по ссылке, существовала в момент обращения к ссылке. Это обычное правило C/С++, когда не нужно передавать во внешний контекст вызываемой функции указатели на локальные объекты, т.к. после выхода из функции эти объекты уже не существуют. UPD. Перечитал цитату. Выше ответил не на этот вопрос. Но принцип там тот же. Да, лямбда -- это такой же объект, как и другие, подчиняется общим правилам. Поэтому если это локальный объект внутри, например, функции, то передавать указатель (или ссылку) на него за пределы функции нельзя. Но вполне можно, к примеру, вернуть такой объект из функции по значению.
  5. []{...} // кратко, если агрументы не нужны [](){...} // полная запись Где вывих мозга? Вместо имени функции используются квадратные скобки и всё. Это выражение можно присвоить переменной -- это будет имя объекта класса-функтора. И передавать это имя (объект класса) везде, где ожидается функция. Попутно можно это выражение написать прямо сразу по месту, что очень удобно. Когда видите такую запись, просто представляйте себе объект класса функтора -- класс, в котором одна-единственная функция-член operator(), которая и вызывается в точке, где ожидается функция. Я скорее не сравниваю, а привожу аналогию с ЯП высокого уровня. Тот же Python не случайно завоевал популярность -- именно благодаря простоте написания и чтения кода. Там вся эта красота даётся весьма высокой ценой -- производительность и размер кода. Хотя и на Python можно писать эффективные программы, если понимать его философию и писать то, что называется pythonic код. Так вот, С++ сделал крупные шаги как раз в сторону возможностей писать код как на ЯП высокого уровня, при этом не теряя присущей ему эффективности. Это даётся нелегко, и если посмотреть на код стандартной библиотеки (или boost), то там всё очень непросто. Но за счёт этого пользоваться этими средствами достаточно просто и безопасно. Такой вот тренд развития С++. Это, имхо, высший пилотаж: позволить писать код в высокоуровневом стиле при сохранении эффективности С.
  6. Это вот эта фигня sizeof(buf)/sizeof(buf[0] более читабельная? 🙂 Он просто вам более привычен, только и всего. В Python циклы от рождения выглядят: for i in seq: ... всем нравится: простая запись итерации по последовательности. Все эти size_t int = 0, ++i, buf[i] и прочее -- это низкоуровневая запись, которая на самом деле загромождает алгоритм: ведь на самом деле мы просто хотим проитерировать по элементам последовательности -- нам нужны именно они по очереди. Вместо того, чтобы сразу получить к ним доступ, нам приходится писать кучу низкоуровневого кода обслуживания индексов и добывания объекта из массива. Вот тут просто вместо in используется двоеточие: for(int x : buf) { ... Запись по стилю очень близка, а по семантике так вообще то же самое. И в отличие от традиционного варианта тут, как и в Python, не нужно менять форму записи при изменении типа последовательности: массив, вектор, строка, список. Попробуйте, вам понравится. 🙂 Сегодня уже трудно найти компилятор, который бы не поддерживал C++11.
  7. Что имеется в виду? Почему с шаблонными это автоматом получится? Шаблон просто является инструкцией для генерации кода, получившийся код обычно предназначен для рантайма. Тут, вроде, нет особой разницы с кодом, сгенерированным по шаблону и написанным руками. Если код можно соптимизировать на этапе компиляции, то это для обоих случаев делается равнозначно.
  8. Для ембеда ещё до кучи consteval для функций, тоже, насколько помню, в C++20 ввели.
  9. У меня тоже было предубеждение сначала. А потом меня товарищ подтолкнул в эту сторону, объяснив, что тот же С++17 -- это хорошо, он делает язык лучше: проще в использовании, безопаснее и более могучим по возможностям. Далее я только убедился в его правоте.
  10. И что такого вечно-геморройного порождает С++11? Можно прям по пунктам пройтись. 1. auto. Возможность автоматического вывода типа. Сокращает писанину, избавляя от необходимости писать длинные квалификации. Особенно полезно с шаблонами. Читабельность кода от этого только улучшается. 2. nullptr. До этого использовался 0 или макрос NULL (что то же самое), иногда это вызывало проблемы -- например, при перегрузке функций. nullptr -- это специальный тип нулевого указателя, избавляет от указанных проблем, выразительность программы только выигрывает. 3. range-based циклы. Два примера: int buf[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; int sum = 0; // example 1 for(size_t i = 0; i < sizeof(buf)/sizeof(buf[0]); ++i) { sum += buf[i]; } // example 2 for(auto &i : buf) { sum += i; } Какой вариант короче, проще писать и читать? Второй вариант является просто синтаксическим сахаром первого и натурально разворачивается в первый. При этом он универсальнее -- позволяет работать с контейнерами, используя итераторы. Там преимущество такой записи проявляется ещё больше. В частности, можно просто заменить массив на std::list<int>, и весь код остаётся прежним. Очевидное улучшение средств языка. 4. Ключевые слова override и final для лучшего контроля над методами (виртуальными функциями) в иерархиях классов. Позволяют избавиться от некоторого класса ошибок. 5. Строго типизированный enum. Вещь, которой мне всегда не хватало! Перечислимый тип в С -- это и не тип никакой, а просто способ создавать именованные литералы. В С++ сразу пошли чуть дальше: по крайней мере объектам типа enum нельзя было просто так присваивать левые значения -- инты, например. Но сами имена значений enum'а загромождали окружающее пространство имён -- всегда нужно помнить, что, например, константу с таким же именем уже не завести. А если пара enum'ов, описывающих состояния конечного автомата, в обоих есть по смыслу одинаковое состояние WAIT, то вот он и конфликт имён сразу же. Строго типизированный enum закрывает эту проблему. enum class рожает значения своего перечислимого типа внутри себя. Если значение нужно использовать снаружи, то оно просто квалифицируется именем этого перечислимого типа, что нативно даёт читабельный и безопасный код. Бесспорное улучшение языка. 6. Интеллектуальные указатели. unique_ptr, shared_ptr, weak_ptr. В значительной степени избавляет от необходимости вообще работать со свободной памятью. 7. Лямбда-выражения. Звучит страшно. На самом деле -- это просто безымянный функтор (функтор -- класс/шаблон, у которого определён operator(), поэтому к нему можно применять операцию вызова, как функции -- () ). В С/С++ функции не являются объектами первого класса (т.е. с ними нельзя обращаться как с объектами в памяти, нельзя создать массив таких объектов), как, например, в языках типа Python или Lua (да почти во всех высокоуровневых языках), концепция функтора устраняет этот недостаток. Благодаря функторам можно делать всякие интересные штуки типа замыканий (closure -- захват контекста), а в качестве предикатов они вообще незаменимы. И это тот самый случай, когда некоторые C++ алгоритмы зачастую работают быстрее, чем их С аналоги -- например, алгоритм std::sort работает быстрее сишной qsort благодаря тому, что функция сравнения в std::sort может передаваться лямбдой, код которой инлайнится. В одном из постов выше я приводил пример использования лямбд в качестве предиката и исполнительной функции. Можно написать то же самое традиционным для С++98 способом, но это будет куда более многословно и громоздко. Лямбды во многом -- это тоже синтаксический сахар вокруг функторов. После небольшой практики использования отказываться от них уже не хочется -- уж очень удобно иметь возможность определять код прямо в месте использования. 8. constexpr. Это вообще маст хэв штука. Особенно для ембеддед. Гарантирует, что значение объекта будет вычислено на этапе компиляции. В более поздних версиях стандарта (по-моему, в C++17) constexpr может использоваться в выражениях if для управления условной компиляцией Наверное, вспомнилось далеко не всё, но и перечисленного более чем достаточно, чтобы без колебаний пользоваться этим (и как минимум ознакомиться с этими средствами). Потому что они делают язык проще и безопаснее в использовании. Никакого вечного геморроя от из применения тут увидеть не могу.
  11. Во-первых, речь в языке программирования, которому, якобы, нет места в будущем и который живёт исключительно за счёт старого кода. Во-вторых, МК бывают разные. В-третьих, про 70-100 раз вы сами придумали? Тут "потери" могут быть только из-за алокации контейнера, ну так замените стандартный алокатор на свой, если хочется скорости. Хотя даже в МК можно и с этим не заморачиваться, если ограничиться урезанной функциональностью контейнера, исключив случаи реалокации -- например, создавая объекты на старте и не меняя их размер. Альтернативный по функциональности код, написанный традиционным способом, будет многословнее, запутаннее и более подвержен ошибкам. В-четвёртых, если вам лично не понятно, что там написано, так это вопрос вашего образования в этой области. Если вам это интересно, вы можете легко расширить познания и взять на вооружение. Если не интересно, просто проходите мимо, не нужно тут свою точку зрения озвучивать как истину. Язык не стоит на месте, развивается. Благодаря этому он становится более мощным в средствах и более простым в использовании при решении одни и тех же задач. Но нужно дать себе труд познакомиться с этими средствами и взять их на вооружение. Конкретно с этим примером? Что там ахрисложного? Вы не знаете, что такое предикат? Или С++ лямбды вызывают не понимание? Да даже не вникая в код, там ясно, что они делают: одна определяет чётность числа, вторая выполняет деление. Из реально нового там только вот эта фишка с ranges, позволяющая формировать цепочки действий -- очень удобная идиома для формирования структур данных. Многие участники форума, я видел, уже давно и успешно используют возможности C++11 (а может и 14), не испугались нововведений, хотя из-за них код программ местами сильно поменялся.
  12. C++ актуален везде, где требуется эффективность и быстродействие. При этом последние версии Стандарта приближают возможности использования к языкам высокого уровня. Например, код Python: numbers_out = [x//2 for x in numbers_in if x%2 == 0] Формирование списка методом фильтрации из входящей последовательности чётных значений с целочисленным делением пополам. Очень удобно и выразительно вот так одной строчкой сформировать объект по правилам. Это делает программу более короткой, более выразительной и сокращает писанину, за что и любят ЯП высокого уровня. Вариант на плюсах (строчек больше, но это потому, что пример полный): #include <iostream> #include <ranges> #include <vector> namespace rng = std::ranges; namespace view = rng::views; std::vector<int> numbers_in = {100, 55, 80, 2, -1}; void f() { auto even = [](int i) { return i%2 == 0; }; auto half = [](int i) { return i/2; }; auto numbers_out = numbers_in | view::filter(even) | view::transform(half); // <---- собственно преобразование for (auto i : numbers_out) { std::cout << i << std::endl; // 50, 40, 1 } При этом всё это работает очень быстро и накладных почти нет: предикаты инлайнятся, код генерится по шаблонам. В этом основная фишка развития С++ -- приблизить использование к ЯП высокого уровня с эффективностью равной или лучшей C. Вообще, использование стандартной библиотеки радикально преображает код программы, избавляя от множества рутинных и опасных операций (работы с памятью напрямую, к примеру). Сохраняя эффективность. Путь развития стандартный: упрощение интерфейса (использования) за счёт усложнения внутренностей (стандартной библиотеки -- там внутри на уровне реализации всё очень непросто).
  13. А как вы обходитесь с созданием таких вещей, которые плотно завязаны на аппаратные блоки ПЛИС? Например, PLL. Не говоря уже о мультигигабитных трансиверах, PCIe блоках, аппаратных МАС и т.п. Да и другие типа памяти или DSP блоков -- да, это можно инферить, но это, имхо, такое себе -- не люблю инферинг за непредсказуемость, когда не там поставленная запятая может сломать его. Да, это не фатально, но неприятно. С Xilinx для памяти и фифо предпочитаю использовать XPM библиотеку -- там тоже внутри инферинг делается, это уже ответственность вендора, "сюрпризов" тут не помню. Если есть "завязки" на аппаратные блоки, то тут как без портирования обойтись? Даже если инферинг успешно используется, всё равно там какие-то вендоро-зависимые атрибуты, как правило, применяются. К сожалению, в той области, где используется продукция Xilinx, уровень требований -- это старшие Kintex из US+, тут BMTI пока не доросли, насколько знаю. А китайские интересуют как раз из области мелочи (аналоги Cyclone, Spartan, ну, может младший Artix). Привлекает доступность, цена. Отпугивает "сырость" и бедность средств разработки.
  14. С помощью какой команды запускаете? В смысле, какой-то проект создаётся или прямо так под управлением скрипта тиклевыми командами? А IP ядра можно создавать консольно -- из скрипта? Или только через его GUI? Интересуюсь, потому что присматриваюсь к китайским ПЛИС. И после Vivado с её довольно богатым Tcl API их инструментарий для консольного управления выглядит как-то бледновато.
  15. 🙂 В этом и ответ. Ква написан на Qt, а Вива на жабе. Она очень медленно запускается (причём старые версии заметно быстрее -- видимо, в новых жаба уж совсем стала жирной и неповоротливой). Но будучи запущенной процесс идёт уже не так медленно. У Вивы консоль запускается дольше, чем та же Квеста успевает откомпилировать небольшой проект. В общем, если будете собирать проекты, которые синтезируются и разводятся хотя бы десятки минут, разница будет не такой радикальной. Если вопросы именно к логическому анализатору, коим является ILA (аналог SignalTap), то какие к нему вопросы? Она вполне функциональная, не уступает визави ни в чём, насколько могу судить. А то, что в Виве нет этого редактора блочной памяти... ну, мне бы тоже хотелось, чтобы такое там было. Но вот такая реальность. Считают, видимо, что это не такая уже киллерфича и мало кому надо (с чем я готов согласиться). Не очень понял, чего хочется. Сохранять дампы прогонов? Вроде такое есть. Но навскидку не подскажу, давно этим не пользовался.
  16. Так сколько часов, минут, секунд собираются проекты в обоих случаях? Там можно сохранить проект в виде тиклевого скрипта (File->Project->Write Tcl...). И потом воссоздать его из этого скрипта. А причём тут память? Речь же про логический анализатор. Если вы имеете в виду In-System Memory Content Editor, позволяющй смотреть потроха блочной памяти, сжирая при этом один физический порт, то такого инструмента в Виваде нет. Но это и не SignalTap.
  17. А какое общее (в смысле -- абсолютное) время сборки там и там? Проект одинаковый? Версия ква какая? У Вивады это вообще один Tcl скрипт. Что там может быть неудобного и сложного, не знаю. Хотя сам предпочитаю вообще всё делать на уровне выше и проекты Вивады генерить на лету по месту. С Ква делали так же. Это избавляет от необходимости хранить кучу лишнего, жрущего место в репозитории, а при любых проблемах с проектом позволяет безболезненно снести его и сгенерить заново. Это вы просто ещё дзен ILA не познали. 🙂 Вот, посмотрите это: Тут вообще управление процессом в значительной степени автоматизируется. Не знаю, предоставляет ли Ква подобные возможности. А это-то зачем вообще? Запуск симулятора вообще намного удобнее и гибче делать отдельно. Там вся "завязка" на конкретную САПР FPGA только на уровне вендорных библиотек, которые нужно один раз откомпилировать и потом просто использовать, настроив доступ.
  18. Всегда так делал (linux), никаких проблем не было. Но недавно надо было закинуть на сборочный сервер 2023, и этот способ не проканал -- не заработало (уже не помню, что именно, валилось с какой-то ошибкой при запуске). Пришлось честно ставить с помощью сетапа в консольном режиме (не сервере нет гуя).
  19. Но встречал упоминание АЦП в женском роде в конексте микроконтроллеров, там такое объяснение не подходит. 🙂
  20. Прошу прощения за офтопик, но не даёт покоя вопрос: почему АЦП часто называют в женском роде. Видел это неоднократно, преимущественно на этом форуме. Ведь АЦП -- аналого-цифровой преобразователь -- преобразователь, мужской род. Ещё могу понять в среднем роде: аналого-цифровое преобразование. Но на женский никаких вариантов в голову не приходит. Можно какое-то пояснение по этому вопросу?
  21. никакой ЯП этого не даёт. Это вопрос? Я нигде, кроме веба жабу не вижу. Ну, ещё Андроид и Эклипс. Того же питона видно вокруг гораздо больше.
  22. А почему не С? Где это java кроме веба? Ой ли? И почему опять не С?
  23. И много в Андроиде C++? Там линукс под капотом, а поверх него жаба. У С++ есть серьёзный недостаток -- этот ЯП сложный. И требуется определённая культура и дисциплина, чтобы код на нём не вышел из-под контроля. А это повышенные требования к квалификации программистов. Которых требуется всё больше, а их средний уровень не очень растёт. Поэтому придумывают новые языки, чтобы снизить порог вхождения и расширить кадровую базу программистов. Пусть ценой некоторой потери эффективности. Но есть немало мест, где поступиться эффективностью нельзя, и это ниша С++.
  24. а на Rust? А что на С не пишут? Где подходит С++, там подходит и С. А может новые языки кое-где таки не тянут по производительности и накладным? А в С++ зачем-то активно новые фичи впиливают. Приближая его про уровню удобства использования к языкам высокого уровня при сохранении эффективности на уровне С.
×
×
  • Создать...