Странное поведение defines - специфично ли это для Arduino и как оно работает?
Вопрос, который у меня давно возник, касается взаимодействия между операторами #define и заголовком библиотеки include . Я видел, как несколько библиотек Arduino использовали эту довольно удобную систему настройки, где вы можете написать
оператор #define, затем включить
инструкцию заголовка #include
, и библиотека изменит свое поведение.
Кто-нибудь знает, почему это работает или не работает? Мое понимание того, как работает #include, заключается в том, что он копирует файл на свое место в новом файле и что код C / C ++ с заголовками должен, таким образом, формировать что-то вроде древовидной формы. Таким образом, имело бы смысл, что любые строки кода, присутствующие до того, как я
#включу
библиотеку, должны быть видны библиотеке, когда препроцессор сделает свое дело и скопирует файл #include
-d.
Но ранее мне говорили, что на самом деле это так не работает (несмотря на реальные примеры, но к тому моменту я уже неуместно разместил библиотеки, которые это делали). Тем не менее, я наконец-то нашел пример того, как кто-то это делает, и я хотел бы знать, как работает такое поведение. Это специфическая особенность Arduino или что-то в этом роде?
Вот библиотека, которая это делает: https://github.com/madpilot/mDNSResolver
@, 👍0
Обсуждение2 ответа
Библиотека mDNSResolver README имеет
Вы можете изменить несколько настроек, определив некоторые константы перед включением заголовочного файла mDNSResolver [в скетч]
Я добавил "в скетче", потому что именно туда вы включаете заголовочный файл mDNSResolver.
Это не сработает, потому что mDNSResolver.cpp , который использует значения defines, компилируется без каких-либо знаний о содержимом файла ino.
Более глубокое объяснение было бы слишком длинным и выходило бы за рамки Arduino SE.
В первых нескольких строках связанного вами файла library .h он проверяет символ, который он не определил, ESP32 (#if defined(ESP32)
) и изменяет компиляцию в соответствии с определенностью этого символа.
Поскольку входные данные компилятора будут представлять собой один длинный файл со всеми файлами #include, уже "вставленными" в строку, у вас (или ранее включенного файла .h) есть возможность предварительно определить эту переменную для изменения компиляции, как это предусмотрено в этой библиотеке writer.
Обновление:
@RDragonflydr: Я полагаю, вы правы, что символ ESP32 определяется компилятором (или, что более вероятно, makefile) для целевого процессора. И чтобы пояснить мое утверждение о том, что "входные данные компилятора будут представлять собой один длинный файл", я имею в виду компиляцию каждого модуля вашего проекта, а не всего проекта сразу. Каждая библиотека будет скомпилирована отдельно, и каждый из ваших модулей будет скомпилирован отдельно, и в каждом из этих случаеввходные данные компилятора будут состоять из кода модуля со всеми включенными файлами #, "вставленными" на место, замененными символами и макросами #defined, а комментарии удалены.
Код библиотеки (.cpp) не #включен, поэтому он не становится частью единицы перевода. Включен только заголовочный файл библиотеки. Это общее - и необходимое - для всех сред и одна из функций препроцессора C или C ++. Это происходит для каждого модуля - отдельно - в многомодульной компиляции. Файлы библиотеки будут
Имея хороший опыт работы в C и C ++ на протяжении многих лет, я совершенно ошеломлен. Вы хотите сказать, что процесс сборки Arduino объединяет все источники скетча в одну большую единицу перевода? Боже, я не знал об этом! Это также верно для библиотек Arduino по умолчанию или просто добавленных библиотек?, @the busybee
Я не совсем понимаю, что вы пытаетесь здесь сказать. AFAIK определение ESP32 устанавливается ядром и / или компилятором Arduino, чтобы сообщить коду, на чем он работает. Это не имеет никакого отношения к определению "настройки", о котором я спрашивал., @RDragonrydr
Я знаю, что процесс сборки Arduino объединяет все файлы - это то, что позволяет определять "настройки" для работы? Я не уверен, есть ли способ заставить это работать в других средах, кроме Arduino IDE. Если это вообще работает, то только в Arduino, и это хрупко, если вы используете другую IDE для кодирования для Arduino?, @RDragonrydr
@thebusybee, только файлы ino в скетче объединяются в один файл cpp, а не файлы C, C ++, S (конечно), @Juraj
- Считается ли #ifdef __SD_H__ плохой практикой?
- #define from main (.ino) не учитывается компилятором в собственных библиотеках
- Не удалось заставить мою созданную библиотеку работать - пока она компилируется
- Как получить исходные файлы для библиотек Arduino?
- Ошибка: "недопустимое использование нестатической функции-члена" при вызове функции из моего собственного класса-метода
- Как подключить Wi-Fi Shield ESP-12E-ESP8266-UART-WIFI-Wireless-Shield к Arduino
- Существуют ли библиотеки сглаживания сигналов для Arduino?
- Wire.h не найден!
Из моего прочтения исходного кода для этой библиотеки я не вижу, что она * может * работать так, как описано. Код библиотеки (файлы cpp) отличается * единицами перевода* от скетча, где будет находиться #define., @Majenko
Можете ли вы объяснить единицы перевода? Я слышал о них, но они кажутся мне очень туманными., @RDragonrydr
Когда вы компилируете файл .c или .cpp, он собирает все содержимое файлов заголовков вместе и буквально заменяет строку на #includes, а затем #defines . Затем компилирует этот один большой результирующий файл. Это единица перевода. Как правило, для каждого файла cpp или c у вас есть одна единица перевода. Это самодостаточная вещь, которая не может быть изменена ничем извне. Единственное исключение - в Arduino, если у вас есть несколько файлов .ino в скетче, они объединяются в одну гигантскую единицу перевода., @Majenko
Если бы я делал то, что вы описываете, я бы использовал класс с конструктором, код которого находится в заголовочном файле и, таким образом, перекомпилируется для каждой единицы перевода (например, внутри скетча). Этот конструктор будет вызываться с помощью макросов, которые вы можете переопределить из скетча, поскольку конструктор является частью того же TU, что и скетч., @Majenko
отсутствующее определение отсутствует не в вашем скетче, оно отсутствует в файле cpp библиотеки, который является его собственным. один изящный трюк, который я использовал, заключается в том, чтобы поместить весь lib-код в H-файл вместо cpp-файла. В результате получается, что код H-файла просто вставляется на место в скетче, что означает, что для него доступны предыдущие определения. Я не знаю, есть ли в этом какие-то недостатки, но все работает так, как я и ожидал..., @dandavis