Директивы #ifdef и #ifndef
- Войдите на сайт для отправки комментариев
Пнд, 21/07/2014 - 19:26
Есть некоторый код. Для примера, сократил до минимума, вместе с комментариями.
У меня 2 платформы. Одна на базе UNO, вторая на базе MEGA. В зависимости от директивы условной компиляции должен прошиваться или UNO или MEGA. Затык в том, что не компилирует. Даю примеры:
1. Компиляция проходит. Все OK.
#define board_MEGA #ifdef board_MEGA const int TestConst = 12; #else const int TestConst = 2; #endif void setup() { } void loop() { } void Func_1() { Func_2(); } void Func_2() { }
2. Комментируем строку //#define board_MEGA. Не компилирует. Выдает ошибку:
Arduino: 1.5.5 (Mac OS X), Board: "Arduino Uno"
Test_03_UNO_MEGA.ino: In function 'void Func_1()':
Test_03_UNO_MEGA:22: error: 'Func_2' was not declared in this scope
//#define board_MEGA #ifdef board_MEGA const int TestConst = 12; #else const int TestConst = 2; #endif void setup() { } void loop() { } void Func_1() { Func_2(); } void Func_2() { }
3. В третьей строке меняем директиву на #ifndef. Опять компилирует.
//#define board_MEGA #ifndef board_MEGA const int TestConst = 12; #else const int TestConst = 2; #endif void setup() { } void loop() { } void Func_1() { Func_2(); } void Func_2() { }
В чем проблема? Не понятно.
PS
Если в третьем примере раскомментировать первую строку - опять ошибка компиляции.
'Func_2' was not declared in this scope
Func_2 нужно объявить до использования
Вообще почитайте что-нибудь по C
Вообщем похоже на заглюк именно самой ArduinoIDE/компилятора.
Что-то похожее у нее происходит при импользовании struct в качестве параметров/возвращаемых значений.
Вынесении объявления struct (в вашем случае этого #ifdef) в отдельный .h файл и его подключение решает проблему (видимо тогда оно понимает что "это честый с-и и не пытается че-то там его перекалапуцать).
Кстати, #define board_MEGA IMHO не самый удобный вариант.
что-то типа
для уны
Будет более удобно. Вот эти макросы __AVR_..... компилятор сам определяет в зависимости от того какая плата сейчас выбрана в Tools/Board. Не нужно ничего править в коде, при компиляции под другую плату.
Вообще почитайте что-нибудь по C
Оп-па... а ну подскажите вот какое "что-нибудь" нужно почитать? По C? Где сказанно что порядок объявления фунций, внутри одного scope имеет значение? Вы часом с javascript не перепутали язык? Мы вообще-то имеет дело с типизированным, компилируемым языком. Который далеко не "в один проход" работает. Вначале лексический анализатор проходит, потом синтаксический, потом из этого строититься AST-дерево, потом.... вообщем тоже можете что-нибудь про компиляторы почитать.
А если из func1() у меня вызывается func2(), а из func2() может вызываться func1(), тогда что читать нужно будет?
P.S. В .ino файлах, особенно когда их несколько, действительно порядок ИНОГДА имеет значение. Но это именно БАГА, а не "ограничение языка". Лечится либо через внешние .h файлы, либо с помощью ключевого слова extern где-нибудь выше использования.
что-то типа
для уны Будет более удобно.
А вот это интересно. Будем играться с этими определениями.
По поводу языка C и места функций, то я, хоть и турист в этом, тоже знал, что место расположения функции в программе значения не имеет. В том коде, который глючил с моими #ifdef, я так и сделал, вынес все мои функции перед Setup. И расположил их в обратном порядке по обращению к ним. Т.е. сначала Func_2, за ней Funk_1 вызывающая Func_2. Но, понимая что это не правильно, все же задал вопрос знатокам.
Спасибо. Будем играться и искать глючки Arduino IDE.
К стати, интересно, у меня Mac OS. А под Windows в IDE те же проблемы?
К стати, интересно, у меня Mac OS. А под Windows в IDE те же проблемы?
Да. Я первым делом проверил ваш код (у меня windows). И функции местами попереставлял (да, хоть "по стандарту" и не играет рояля, а иногда помогает) и еще всякое попробовал. Например если Serial.println(TestConst), то мне кричало что "unknown Serial".... вообщем совершенно невообразимые ошибки валились. Похоже что, почему-то срывает ему башню и какая конкретно ошибка вылезет - значения не имеет.
И вынос в .h файл попробовал - убедился что "это помогает" в вашем случае.
Есть параллельная тема, где, возможно, подобная лажа (проблема ArduinoIDE)
http://arduino.ru/forum/programmirovanie/oshchibka
там я приводил пример, что делает ArduinoIDE из исходного текста, рекомендую посмотреть и в этом случае.
Если кто не знает или не помнит, то добавляем в preferences.txt строку (ArduinoIDE должен быть закрыт, кто не знает где лежит preferences.txt гуглите):
build.path=build
Создаем в каталоге, где установлена ArduinoIDE подкаталог build.
После этого в данном подкаталоге после компиляции лежат все файлы, которые создавались в процессе компиляции. Нужно искать файл с именем скетча и расширением .cpp, отчасти удивляться, отчасти говорить "эврика", вспоминая, что когда то давно это читал и знаю.
Возможно я ошибаюсь, но можно попинать монитор, если кто хочет.
Сделал и с этими определениями #if defined (__AVR_ATmega1280__) || defined (__AVR_ATmega2560__)
и с заголовками .h
Вес проблемы решены. Стало супер удобно: меняешь тип платы в IDE и дальше ни о чем не заботишься.
Вес проблемы решены. Стало супер удобно: меняешь тип платы в IDE и дальше ни о чем не заботишься.
А фиг там.... в вашем случае - да. А у меня, скажем, нужно отличать Leonardo и Pro Micro. И оба на 32u4. Но при этом какие ноги выведены, а какие нет - различается.... вообщем-то есть идеи как.... но нужно будет еще разбираться с этим.
leshak, да уж, задачка.. Думаю Вы уже заглянули в каталог
D:\Programs\Arduino-1.0.5\hardware\arduino\variants\micro
хотя по этим файлам ничего не определишь, всё как то через одно место..
И еще есть комментарий в загрузчике, что у Микро полярность светодиодов на RX TX обратная :) Ага это сильно поможет, конечно :)
UPD Разве что если загрузчик можно поменять, то было бы проще. Еще вариант с EEPROM, но это хуже, ИМХО
leshak, да уж, задачка.. Думаю Вы уже заглянули в каталог
D:\Programs\Arduino-1.0.5\hardware\arduino\variants\micro
Да бегло смотрел, где-то там видел что дефайнится что-то типа ___coreXXXX, но вот попробовать - не успел.
Или у tennesy что-то такое было...., ну в конечном итоге думаю в любом случае через variants можно будет реализовать. Вопрос только в том "сколько самому дописывать".
Через variants думаю и две одинаковые платы можно будет отличать (выбирая их в Tools/Boards), которые вообще отличаются "только именами". Но тогда прийдется эти variants плодить....
Хотя... в идеале конечно бы-бы найти какой-то дефайн который прямо из board.txt берет имя секции....
nano328.name=Arduino Nano w/ ATmega328
Но подозреваю, что вряд ли это есть в arduinoIDE.
А если бы они еще реализовали, в boards.txt "наследование плат....". Хотя, вообщем-то можно и препроцессор какой-топ прикрутить, который из boards.tempalte генерит boards.txt :) и там уже "что душа пожелает твори..".
А еще хочется какой-то PreBuild Event и PostBuildEvent иметь и вешать на них свои скрипты... Вот тогда точно "делай что хочешь".... :)
Заканчивая оффтоп, пришла такая простая мысль, можно сделать в pins_arduino в каталоге micro дефайн, который точно определит, что это micro :) Самое тупое, на мой взгляд.
Заканчивая оффтоп, пришла такая простая мысль, можно сделать в pins_arduino в каталоге micro дефайн, который точно определит, что это micro :) Самое тупое, на мой взгляд.
Ну дык это и есть то что я описал "через variants"... но не хочется плодить сущности. Вначале хочу убедитяся/полазить что точно нет "способа из коробки", не внося изменений в папку Arduino....
Бо потом дашь кому-то... а у него нет "таких поправок", или сам в соседнюю папочку распакуешь еще одну версию ардиуны..., а там "магической добавочки" - нет (у меня их уже как у бобика блох версий ArduinoIDE/библиотеки :)
P.S. А чего вы это offtop обозывали? Помоему наше обсуждение довольно неплохо укладывается в рамки изначальной задачи "нужно определять под какую плату компилимся".
Ну раз не оффтоп, тогда делаем открытия. Я, собственно и сам не знал, спасибо за науку, нашел решение.
Оказывается тупее не придумаешь решения, делать ничего не нужно совсем, пример:
Я и сам не знал, чтобы узнать, достаточно было увидеть строку компиляции:
Разумеется смотрим на эту часть (здесь для Леонардо):
Это явно берется из boards.txt (я не пробовал)
Пробовал в среде выбирать нужный board и получал разные сообщения.
UPD: Кусок из board.txt для Леонардо
Да. Действительно. Наврал. Можете не принимать к сведению мой комментарий. :)
Вот во что разворачивает Arduino IDE скетч
Подскажите, откуда компилятор узнает про эти директивы?
#if defined (__AVR_ATmega1280__) || defined (__AVR_ATmega2560__)
конкретно __AVR_ATmega1280__ и __AVR_ATmega2560__. Мне очень интересно в каком файле это написано. Как компилятор узнает что это AVR_ATmega1280?
Читайте Кернигана и Ритчи
Вы сами ему сообщаете, выбирая в среде процессор под который компилируется программа.
Спасибо,почитал я Кернигана и Ритчи, но не нашел там ответа на свой вопрос. Дело в том что я ковыряю библиотеку RF24,там есть такие строки
Спасибо,почитал я Кернигана и Ритчи, но не нашел там ответа на свой вопрос.
Вы его не прочитали. Полностью, от начала до конца, разбирая примеры. Прочитайте и всё найдёте.
Вот так работает:
Подсмотрел тут