как использовать #ifdef в CPP файле ???

vde69
Offline
Зарегистрирован: 10.01.2016

суть проблеммы:

от основной программы отделил файл #include "A_Config.h", именно в этом файле устанавливаю #define DATE_TIME_USE (переносить установку в основной модуль очень не хочется)

далее я хочу, что-бы в CPP файла проекта (там их много) работала директива #ifdef DATE_TIME_USE

но тут проблемма, cpp файлы собираются все вместе еще до обработки #include "xxx.h" и по существу весь мой код вырезается а только потом устанавливается директива #include

какие будут предложения?

я пока вижу следующие варианты:

1. отказатся от использования файла A_Config.h и все перенести в основной файл, но мне не нравится это

2. перенести весь код CPP в H файл, но я не понимаю чем это грозит. На вскидку могут быть проблеммы с видимостью объектов... 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Какую-то фигню вы написали. ВСЕ заголовочные файлы, подключённые как в *.h, так в *.cpp и в *.ino - разбираются _до_ начала обработки собственно исходников. Юзаю препроцессорные директивы в хвост и в гриву, версия IDE 1.6.7, всё прекрасно собирается.

Можете проверить на простом тесте:

1. Файл A_Config.h:

#ifndef _A_CONFIG_H
#define _A_CONFIG_H

#define DATE_TIME_USE

#endif

2. Файл Some.h:

#ifndef _SOME_H
#define _SOME_H
#include "A_Config.h"

class Test
{
public:
Test();
void out();
};


#endif

3. Файл Some.cpp:

#include "Some.h"

Test::Test()
{
}

void Test::out()
{
#ifdef DATE_TIME_USE
Serial.begin(9600);
Serial.println("It's alive!");
#endif
}

4. Файл *.ino проекта:

#include "Some.h"

void setup()
{
 Test test;
  test.out();
}

И прошить в МК. Если определена директива DATE_TIME_USE - то в Serial должна вывестись строка, если директиву закомментировать и пересобрать прошивку - строки не будет. Писал навскидку, думаю, принцип понятен.

vde69
Offline
Зарегистрирован: 10.01.2016

ну я почти так и делал, вся разница в том, что у Вас в cpp под директиву убраны 2 строки внутри процедуры а я убирал всю процедуру целиком, и компилятор банально выдавал ошибку вне зависимости от наличия DATE_TIME_USE

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

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

пока остановился на таком варианте, условие на 26 строке


#ifndef A_HOUSE_ADDON_H        
#define A_HOUSE_ADDON_H

#include  
#include 


// ------------------------------------------------------------
// Описания использемых типов данных и зон где они получены/действуют
#define TYPE_UNDEFINED        0   // неопределено
#define TYPE_DATE_TIME        1   // Тип данных - дата и время, 7 байт                   
#define TYPE_TERM             2   // Тип данных температура, 2 байта                   

#define ZONE_UNDEFINED        0   // неопределено
#define ZONE_ALL              1   // везде                   
#define ZONE_OUTD0OR          2   // на улице                   
// ------------------------------------------------------------

// ------------------------------------------------------------
// Описания функций используемых в объектах и в проекте
unsigned long getDelayTime(unsigned long start_time, unsigned long end_time);



// ------------------------------------------------------------
#ifdef DATE_TIME_USE    
const uint8_t daysInMonth [12] PROGMEM = { 31,28,31,30,31,30,31,31,30,31,30,31 };    
    
class addon_DateTime {
private:

  long time_to_long(uint16_t Y, uint8_t M, uint8_t D, uint8_t h, uint8_t m, uint8_t s) // количество секунд после 2000/01/01, действительно для периода 2001..2099
  // *********************************************************
  {
    if (Y >= 2000)
        Y -= 2000;
    uint16_t days = D;
    for (uint8_t i = 1; i < M; ++i)
        days += pgm_read_byte(daysInMonth + i - 1);
    if (M > 2 && Y % 4 == 0) ++days;
    days = days + 365 * Y + (Y + 3) / 4 - 1;
    return ((days * 24L + h) * 60 + m) * 60 + s;
  }
  // *********************************************************

public:
  
  uint16_t year()        { return 2000 + yOff; }
  uint8_t month()        { return m; }
  uint8_t day()          { return d; }
  uint8_t hour()         { return hh; }
  uint8_t minute()       { return mm; }
  uint8_t second()       { return ss; }

  void SetDateTime ()
  // ********************************************************
  {
    long lt2 = offset + (millis() / 1000);
    if (lt > lt2) {              // видимо был переход через 0 счетчика millis()
      offset = offset + 4294967; // это примерно 47 дней, что равно времени переполнения счетчика millis() 
      lt = offset + (millis() / 1000);
    }
    else {
     lt = lt2;
    }

    lt2 = lt;
    ss = lt2 % 60;
    lt2 /= 60;
    mm = lt2 % 60;
    lt2 /= 60;
    hh = lt2 % 24;
 
    uint16_t days = lt2 / 24;
    uint8_t leap;
 
    for (yOff = 0; ; ++yOff) {
      leap = yOff % 4 == 0;
      if (days < 365 + leap)
         break;
      days -= 365 + leap;
    }
    for (m = 1; ; ++m) {
      uint8_t daysPerMonth = pgm_read_byte(daysInMonth + m - 1);
      if (leap && m == 2)
         ++daysPerMonth;
      if (days < daysPerMonth)
         break;
      days -= daysPerMonth;
    }
    d = days + 1; */
   }
  // ********************************************************
  
  void SetDateTime (uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec)
  // ********************************************************
   {
     if (year >= 2000)
         year -= 2000;
     yOff = year;
     m = month;
     d = day;
     hh = hour;
     mm = min;
     ss = sec;
     lt = time_to_long(yOff, m, d, hh, mm, ss); 
     offset = lt - (millis() / 1000);
   }
  // *********************************************************
  
  void poll(unsigned long time_loop)
  // *********************************************************
   {
     long a = time_loop / 1000;
     if ((lt - offset) != a) { SetDateTime(); }  
   }
  // *********************************************************

protected:
  uint8_t yOff, m, d, hh, mm, ss; // хранит дату/время
  long lt;                        // хранит дату/время в секундах после 2000/01/01
  long offset;                    // хранит количество секунд после 2000/01/01 на время последнего обнуления счетчика millis()
};

#endif 

#endif 



DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

vde69 пишет:

ну я почти так и делал, вся разница в том, что у Вас в cpp под директиву убраны 2 строки внутри процедуры а я убирал всю процедуру целиком, и компилятор банально выдавал ошибку вне зависимости от наличия DATE_TIME_USE

Значит, неправильно делали. Переписать вам мой пример с обрамлением всей процедуры?

 

1. Файл A_Config.h:

#ifndef _A_CONFIG_H
#define _A_CONFIG_H

#define DATE_TIME_USE

#endif

2. Файл Some.h:

#ifndef _SOME_H
#define _SOME_H
#include "A_Config.h"

class Test
{
public:
Test();
#ifdef DATE_TIME_USE
void out();
#endif
};


#endif

 

3. Файл Some.cpp:

#include "Some.h"

Test::Test()
{
}

#ifdef DATE_TIME_USE
void Test::out()
{
Serial.begin(9600);
Serial.println("It's alive!");
}
#endif
 

4. Файл *.ino проекта:

#include "Some.h"

void setup()
{
 Test test;
#ifdef DATE_TIME_USE
  test.out();
#endif
}

 

 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

vde69 пишет:

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

Что значит "может и взлетит"? Куда оно денется - это же препроцессор, если понимать, как его использовать и почитать документацию - практически никаких ограничений, надо только грамотно юзать. Можно и весь класс убрать из компиляции, не вопрос. Проблем не вижу вообще, вернее, вижу одну проблему с вашей стороны - непонимание того, как работает препроцессор. Чуть-чуть разберётесь - и всё получится ;)

vde69
Offline
Зарегистрирован: 10.01.2016

sketch\a_house.ino.cpp.o: In function `loop':

D:\arduino\mu_progect_169\a_house/a_house.ino:199: undefined reference to `addon_DateTime::poll(unsigned long)'

collect2.exe: error: ld returned 1 exit status

exit status 1

Ошибка компиляции для платы Arduino Nano.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Правильно, осталось только поправить эту ошибку, и всё. Вы вызываете функцию, которая была исключена директивами препроцессора. Если обрамить вызов этой фунции теми же директивами препроцессора, то вызов этой функции не попадёт в результирующий код.

Вы мой пример-то пробовали, или сразу кинулись готовый проект портить? Без понимания, как работают директивы препроцессора - не взлететь.