Ошибка компиляции при использовании #ifdef`а

v1ad54
Offline
Зарегистрирован: 21.08.2015

Приветствую уважаемых форумчан!

Столкнулся с непонятным мне поведением компилятора при использовании #ifdef`а...

Посмотрите первый скетч:

void setup(){
 
}

void loop() {

}

Как и ожидалось скетч успешно скомпилировался:

Sketch uses 450 bytes (1%) of program storage space. Maximum is 30 720 bytes.
Global variables use 9 bytes (0%) of dynamic memory, leaving 2 039 bytes for local variables. Maximum is 2 048 bytes.
 
Усложним наш скетч:
int  a;

void setup(){
 
}

void loop() {

}

Скетч опять успешно скомпилировался:

Sketch uses 450 bytes (1%) of program storage space. Maximum is 30 720 bytes.
Global variables use 9 bytes (0%) of dynamic memory, leaving 2 039 bytes for local variables. Maximum is 2 048 bytes.
 
Обложим теперь объявленную переменную #ifdef`ом:
#ifdef A
  int  a;
#endif

void setup(){
 
}

void loop() {

}

Компиляция этого скетча приводит к ошибке:

Изменена опция сборки, пересобираем все
C:\Users\vlad\AppData\Local\Temp\build582594788212757414.tmp/core.a(main.cpp.o): In function `main':
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/main.cpp:40: undefined reference to `setup'
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/main.cpp:43: undefined reference to `loop'
collect2.exe: error: ld returned 1 exit status
Ошибка компиляции.

Удивляемся и продолжаем эксперементировать. Определим теперь A что бы задействовать в программе содержимое #ifdef`а:

#define A
#ifdef A
  int  a;
#endif

void setup(){
 
}

void loop() {

}

Компиляция успешна:

Изменена опция сборки, пересобираем все
Sketch uses 450 bytes (1%) of program storage space. Maximum is 30 720 bytes.
Global variables use 9 bytes (0%) of dynamic memory, leaving 2 039 bytes for local variables. Maximum is 2 048 bytes.
 
Закоментируем теперь #define A:
//#define A
#ifdef A
  int  a;
#endif

void setup(){
 
}

void loop() {

}

Компиляция вновь с ошибкой:

Изменена опция сборки, пересобираем все
C:\Users\vlad\AppData\Local\Temp\build582594788212757414.tmp/core.a(main.cpp.o): In function `main':
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/main.cpp:40: undefined reference to `setup'
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/main.cpp:43: undefined reference to `loop'
collect2.exe: error: ld returned 1 exit status
Ошибка компиляции.
 

Ну и еще один скетч, закоментируем переменную:

//#define A
#ifdef A
//  int  a;
#endif

void setup(){
 
}

void loop() {

}

Компиляция успешна:

Изменена опция сборки, пересобираем все
Sketch uses 450 bytes (1%) of program storage space. Maximum is 30 720 bytes.
Global variables use 9 bytes (0%) of dynamic memory, leaving 2 039 bytes for local variables. Maximum is 2 048 bytes.
 
Как можно объяснить такое поведение компилятора?
Как переменная внутри #ifdef`а, содержимое которого итак не должно в итоге попасть в скопилированный код, влияет на функции setup и loop?
Версия Arduino IDE 1.6.5.
 
PS: Не подумайте что я просто извращаюсь... Я написал код в котором активно использую #ifdef`ы для управления конфигурациями разных сборок и при тестировании натолкнулся на эту ошибку. Теперь пытаюсь понять в чем тут дело...
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Влад, я уже не в первый раз здесь пишу об этом ...

Эти мчудаки - авторы IDE решили облегчить жизнь новичкам ... серия непечатных слов ... Ради этой этой благородной цели они решили своим препроцессором вручную собирать по коду все заголовки функций и помещать вначале их (функций) предварительные объявления. Мол, типа, при таком подходе новичок может не париться, что у него функция используется до объявления - мы мол ему поможем ... серия непечатных слов ...

В результате возникают ошибки типа Вашей. Вот смотрите, у Вас было:

#ifdef A
int a;
#endif

void setup(){}

void loop() {}

а вот, что эти казлы нехорошие люди передают настоящему компилятору gcc после своего грёбанного препроцессора:

#ifdef A
#include "Arduino.h"
void setup();
void loop();
#line 2
int a;
#endif

void setup(){}

void loop() {}

Понятно теперь почему не компилируется? Спасибо авторам IDE ... серия непечатных слов, переходящая в понос словесный и не только ...

В Вашем случае бороться с этим несложно - достаточно, чтобы #ifdef не был первым в программе. Например, вот так вполне сработает:

int b;

#ifdef A
int a;
#endif

void setup(){}

void loop() {}

Если интересно, могу привести ещё один код, который "необъяснимо" не компилируется, благодаря всё той же дурацкой инициативе - собирать в начало все объявления.

Смотрите, сначала я объявляю класс, а потом его использую, как делают все нормальные люди! Но из-за того, что эти казлы нехорошие люди перетащили в самое начало объявление функции, всё летит к чертям и компилятор ругается (и правильно делает). Вот пример:

class Kaka {
	public: Kaka(void) {}
};

void func(Kaka *k) {

}

void setup(){}

void loop() {}

 

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Ух-ты .. не я один авторов "добрым словом" помянул .. :)

Да, это феноменальное решение. Пошукайте, в сети есть настройки к Эклипсу для компиляции и прошивок БЕЗ использования ИДЕ. Помогает. :)

v1ad54
Offline
Зарегистрирован: 21.08.2015

Евгений, спасибо большое за объяснение!

Да, действительно еще одна переменная вне #ifdef`а спасает...
Остается только один вопрос - зачем они засунули свои объявления в МОЙ #ifdef? Разве не могли поднять свои объявления на самый верх?

И еще... Евгений а как вы дошли до этой мысли? :) Где то можно увидить результат работы препроцессора?

PS: Предварительно искал поиском темы с такой ошибкой, но там были темы с явными ошибками разработчика, а не компилятора. Возможно был не внимателен, пропустил...
 

v1ad54
Offline
Зарегистрирован: 21.08.2015

Все, понял... В темпе нашел файлик (результат Вашего примера):

#line 1 "sketch_nov21a.ino"
#include "Arduino.h"
void func(Kaka *k);
void setup();
void loop();
#line 1
class Kaka {
  public: Kaka(void) {}
};

void func(Kaka *k) {

}

void setup(){}

void loop() {}

Забавно...

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

v1ad54 пишет:

И еще... Евгений а как вы дошли до этой мысли? :) Где то можно увидить результат работы препроцессора?

Дошел случайно. Заметил. что я ошибся (использовал функцию до объявления), а компилятор "схавал". Дальше по Гоголю "Э-э-э сказали мы с Петром Ивановичем" ... и полез смотреть

Посмотреть легко.

1. В файле настроек IDE preferences.txt недалеко от начало есть строка "build.verbose=false". Замените false на true.
2. В том же файле пониже есть "preproc.save_build_files=true" - убедитесь, что true. 

(ВНИМАНИЕ! Этот файл можно редактировать только при полностью закрытом IDE - все окна закрыть).

После этого запускайте IDE - он при компиляции станет ОЧЕНЬ болтливым. Среди всей болтовни найдёте назвние файла типа <имя Вашего скетча>.ino.cpp - там он будет с полным путём (путь весьма извилистый). Вот это он самый и есть - файл, который уходит настоящему компилятору после всех IDE'шных извращений. Именно его я Вам и процитировал выше.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

v1ad54 пишет:

Все, понял... В темпе нашел файлик (результат Вашего примера):

Во-во! Видите, использование класса Kaka оказалось выше его определения. Понятно, что компилятор ругается на меня, а я на авторов IDE.

v1ad54
Offline
Зарегистрирован: 21.08.2015

Эту же настройку можно поправить в меню Файл \ Настройки и там "Показывать подробный вывод".
Похоже это одно и то же... Тоже стал "болтливый".

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

ЕвгенийП, хотелось бы попросить Вас зайти в тему http://arduino.ru/forum/programmirovanie/arduino-kak-konechnyi-avtomat-z...

Там у человека проблема с компиляцией из под винды в версии ИДЕ 1.5.2 моей либы.. но только вот не понимаю что там вообще происходит, а проверить нет возможности.. заранее, спасибо.

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

А ещё, если в preference.txt определить build.path=build и создать в каталоге, где установлена ArduinoIDE подкаталог build, то можно в нём после компиляции найти интересные файлы. Это удобней, нежели рыться в тэмпе.
Опять же удобно оттуда подтягивать hex файл в Proteus, например.

v1ad54
Offline
Зарегистрирован: 21.08.2015

kisoft пишет:
А ещё, если в preference.txt определить build.path=build и создать в каталоге, где установлена ArduinoIDE подкаталог build, то можно в нём после компиляции найти интересные файлы. Это удобней, нежели рыться в тэмпе. Опять же удобно оттуда подтягивать hex файл в Proteus, например.

Спасибо, добрый человек! Будем знать. :)

leko
Offline
Зарегистрирован: 17.12.2015

Разрабатываю контроллер для своей муфельной печи.

Натолкнулся на "бред какой-то"...

Создал пустую функцию void Mbut4(void){

}

и пустую переменную knopki[4];

Попытался компильнуть...

Пишет:

collect2.exe: error: ld returned 5 exit status
Ошибка компиляции.

... и вываливаектся!

Посмотрел файлы (как описано выше) - там все нормально...

#line 1 "mufel16_006.ino"
                                                                        
   

# define MAXMAX 3

                           
#include "Arduino.h"
void WriteMax_byte(unsigned char Data);
void Minit(void);
void Mclear(void);
void Mdrow(void);
void MsdvigL(int poz);
void Mtype(int nn);
void Mslova(int nn);
void Mblink(void);
void Mnum4(int num);
void Mnum2(int indik,int num);
void Mbut4(void);
void setup();
void loop();
#line 7
int Max_pinCLK = 12;
int Max_pinCS  = 11;
int Max_pinDIN = 10;

int mblink[MAXMAX];
int cou_blink=0;
int cou_stop_blink=100;
int knopki[4];

unsigned char pole[8*MAXMAX];                                         

unsigned char znak[12][4]={               
{ 0x00,0xfe,0x82,0xfe},     
{ 0x00,0x08,0x04,0xfe},     
{ 0x00,0xc6,0xa2,0x9e},     
{ 0x00,0x92,0x92,0xfe},     
{ 0x00,0x1e,0x10,0xfe},     
{ 0x00,0x9e,0x92,0xf2},     
{ 0x00,0xf8,0x94,0xf2},     
{ 0x00,0xe2,0x12,0x0e},     
{ 0x00,0x6c,0x92,0x6c},     
{ 0x00,0x9e,0x52,0x3e},     

{ 0x00,0x10,0x10,0x10},         
{ 0x00,0x10,0x38,0x10},         
};
 

и далее...

При закомментировании функции или переменной все начинает работать.

(всего лишь добавилась аналогичная функция и переменная)

Правил preferences.txt - ничего не изменилось

закомментировал "все новое" - "бздец"! Перестал скетч работать! ( предыдущая версия компилируется и грузится и работает)

Я 25-20 лет назад, писал на С и С++ . Может подскажите попроще редактор-компилятор, что б вспомнить, работать и не "материться"... версия 1.6.4... попробую поставить завтра 1.6.7... )

Разработка встала мертво! (

 

leko
Offline
Зарегистрирован: 17.12.2015

Сейчас "нарыл" Code::Blocks c поддержкой arduino...
Тестовую программу прогнал... Пойду дальше разбираться... Вроде все просто )))

P.S. Прошло 20 мин и я уже разобрался и перегрузил проект "Контроллера Муфельной печи" из CodeBlocks без ошибок и вываливаний... Ура!!! )))