Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Микроконтроллеры (MCU) и микропроцессоры (MPU) > что такое #ifndef


Автор: CROC 20.1.2007, 13:28
для чего:
Код

#ifndef _SPI_LIB_H_
#define _SPI_LIB_H_

а так же 
#ifdef
#endif

в моем простеньком учебничке такого не нашел smile

Автор: Rodman 20.1.2007, 14:44
Встретив одну из первых двух директив, препроцессор проверяет, определено ли символическое_имя, и, в случае с #ifdef отдает компилятору последующие строки, только если оно определено, в случае же с #ifndef — наоборот, только если не определено. Так он поступает со всеми строками до тех пор, пока не встретится #else или #endif. Собственно, #ifdef и #ifndef — это сокращения от аглийских фраз if defined («если определено») и if not defined («если не определено»). Инструкция #else, как и ее аналог в упомянутом операторе ветвления, переводится как «иначе» и действует аналогично (в частности, директива эта тоже не обязательна). Ну а #endif в переводе означает «конец «если»». Кстати, блоки директив #if...#else...#endif, как и их операторные тезки, могут быть вложенными — таким образом, на определенность-неопределенность директив тоже можно налагать сколь угодно сложные условия.

http://www.mycomp.com.ua/text/5034;jsessionid=3B115C59CEAA765F2ED7558235165A71

Автор: skyboy 20.1.2007, 16:21
CROC, одно из применений - кроссплатформенный компилинг. представь, что у тебя код отличается 5 десятками строк под два разных контроллера. как будешь делать? вести параллельно две копии практически одинакового кода? будет головная боль с синхронизацией... А так: делаешь, например:
Код

#define MK1560

и потом в коде делаешь вилку не на if, которые будут компилироваться и влиять на итоговый размер, а #ifndef:
Код

#ifdef MK1560
int i;
#endif
#ifdef MK1565
char i;
#endif

В конечном итоге для компилирования под некую МК1565 надо будет только сменить строку "#define MK1560" на "#define MK1565" и приложение будет скомилировано уже под МК1565. И при любом режиме компилироваться будет только то, что необходимо. В исполняемом коде - ни одного линего байта.
Однако, при таком подходе надо следить, чтоб не было противоречивых объявлений: в приведенном примере
Код

#define MK1560
...
#define MK1565

могут сделать программу полностью неработоспособной.
Второй вариант использования: для дебагинга. Сделать так, что некоторые строки будут компилироваться, только если определение есть. Убрал определение - код дебага не компилируется даже. Удобно.
Третий вариант, который видел, но сам не использовал - предотвращение #include'инга модуля несколько раз: сделать так в самом модуле "#define my_module_1", а так в программе:
Код

#ifdef my_module_1
#include <mymod>
#endif

И модуль будет вкомпилен только разово. Правда, об этом слышал на лекции по BС++ 3.0, наверняка современные компиляторы предотвращают такую ситуацию...

Автор: CROC 20.1.2007, 19:11
Всем большое спасибо!!!
как я понял эта логика нужна для компиляции и отладки, а не для работы самой программы

Автор: PILOT 20.1.2007, 19:31
Ребята, молодцы, очень хорошо объяснили все!

СУВ.

Автор: Кристиан 3.2.2007, 11:22
Такая комбинация нужна еще для того, чтобы не было повторных включений заголовочных файлов.

Автор: EvilsInterrupt 26.7.2009, 10:03
недавно задал массив строк:

Код

typedef enum ERROR_IO {
//
//
// 
  EIO_COUNT
} *PERROR_IO ;

char * error_io_messages[EIO_COUNT] = 
{
 "Stream open failed",
///
///
///
};


и все это задекларировал в инклуде exceptions_io.h , который включал в другие *.cpp файлы помимо exception_io.cpp и был поражен тем, что находилось два массива error_io_messages. Только потом меня  любезный Lazin просвятил, что в инклудах,который включаются в другие файлы не следуют объявлять реальные переменные ! Т.е вывод: инклуды это декларация структур, классов, енумы и т.д. и т.п. 

Автор: UniBomb 27.7.2009, 08:27
EvilsInterrupt, вообще непонятно к чему ты апнул эту тему, но:

Цитата(EvilsInterrupt @  26.7.2009,  10:03 Найти цитируемый пост)
был поражен тем, что находилось два массива error_io_messages

Что бы этого избежать нужно использовать "стражей повторного включения". Т.е. что то типа такого:


Код

#ifndef _exceptions_io_h_
#define _exceptions_io_h_

typedef enum ERROR_IO {
//
//
// 
  EIO_COUNT
} *PERROR_IO ;

char * error_io_messages[EIO_COUNT] = 
{
 "Stream open failed",
///
///
///
};

#endif

Автор: xvr 27.7.2009, 13:52
Цитата(UniBomb @ 27.7.2009,  08:27)
EvilsInterrupt, вообще непонятно к чему ты апнул эту тему, но:

Цитата(EvilsInterrupt @  26.7.2009,  10:03 Найти цитируемый пост)
был поражен тем, что находилось два массива error_io_messages

Что бы этого избежать нужно использовать "стражей повторного включения". Т.е. что то типа такого:

В данном случае это не поможет - вот это
Цитата

Код

...
char * error_io_messages[EIO_COUNT] = 
...

создаст по массиву error_io_messages в каждой единице трансляции, что приведет к слому на этапе линковки (о чем EvilsInterrupt и написал)


Автор: UniBomb 27.7.2009, 15:12
Цитата(xvr @  27.7.2009,  13:52 Найти цитируемый пост)
В данном случае это не поможет

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

Автор: xvr 27.7.2009, 19:15
Цитата(UniBomb @ 27.7.2009,  15:12)
Цитата(xvr @  27.7.2009,  13:52 Найти цитируемый пост)
В данном случае это не поможет

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

Повторного включения не будет, файл будет включен ровно 1 раз В КАЖДОЙ единице компиляции. А так как в нем error_io_messages не extern описание а именно определение переменной, то она появится в каждой единице компиляции, куда был включен исходный заголовочный файл


Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)