Домашняя страница библиотеки_c AVR

Синтаксис языка C

Библиотека языка C GNU glibc

 Страницы развития библиотеки_с AVR

Главная страница

Инструкция пользователя

Содержание библиотеки_c

Часто задаваемые вопросы

Содержание по алфавиту

Демонстрационные проекты


 

Директивы условной компиляции

Многие микроконтроллеры отличаются лишь некоторыми параметрами, ко­личеством выводов, размером памяти и размещением регистров. Это позволяет создавать на языке C программный код для всего модельного ряда. Однако для этого следует каким-то образом заменить те параметры, которые отличаются у разных моделей. Для таких целей используются директивы условной компиляции.

#ifdef,   #ifndef,   #else   и   #endif,   а   также   #if   и   #elif.

 

Синтаксис для директивы #ifdef:

#ifdef имя_макроса   последовательность_операторов_1

#else   последовательность_операторов_2

#endif

Если имя макроса определено в программе, то компилируется первая после­довательность операторов, в противном случае — вторая последовательность (ветка #else может и отсутствовать).

Пример использования (для компилятора CCS-PICC):

#define   DEBUGGINGJDN

#ifdef   DEBUGGING_ON

fuse   rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)

#endif

 

Синтаксис для директивы #ifndef:

#ifndef  имя_макроса   последовательность_операторов_1

#else   последовательность_операторов_2

#endif

В данном случае, в отличие от директивы #ifdef, первая последовательность операторов выполняется в том случае, если имя макроса не опреде­лено в программе.

 

Для условной компиляции можно также воспользоваться директивами   #if,   #elif.

Их синтаксис:

#if выражение1   последовательность_операторов_1

#elif выражение2   последовательность_операторов_2

#else   последовательноеть_операторов_3

#endif

Эта конструкция работает аналогично условному оператору if-else. Компи­лятор оценивает выражения после #if и #elif до тех пор, пока одно из них не даст в результате TRUE, после чего в текст программы подставляется соответст­вующая последовательность операторов. Если оба выражения дают false,  то подставляется последовательность операторов после директивы #else (если она присутствует).

Допустим, для передачи и приема данных через UART у абстрактного микро­контроллера SomeMicl6 используются выводы 12 и 13, у микроконтроллера SomeMic8 — выводы 6 и 14, а у SomeMic4 — выводы 1 и 2. Тогда мы можем соз­дать заголовочный файл SomeMic.h и включить в него следующие директивы.

#if SomeMicX == 16

#define TXD 12

#define RXD 13

            #elif SomeMicX == 8

#define TXD 6

#define RXD 14

            #elif SomeMicX == 4

#define TXD 1

#define RXD 2

            #else

#error "Pins TXD и RXD for SomeMicX are not defined"

            #endif

Теперь, если программный проект будет построен на микроконтроллере SomeMic8, то в заголовочный файл следует поместить следующий текст.

#ifndef   SomeMicX

#define   SomeMicX  =   8

#include   <SomeMic.h>

#endif

Встретив директиву #ifndef, препроцессор включит в текст программы #define SomeMicX = 8 и #include <SomeMic.h>. Поскольку после этого эле­мент SomeMicX получит значение, равное 8, то любая повторная обработка дирек­тивы #ifndef не приведет к дублированию в выходном тексте соответствующей информации. Другими словами, содержимое заголовочного файла SomeMic.h бу­дет помещено в исходный код файлов, использующих заголовочный файл с #ifndef, только один раз.

Использование директивы #ifndef с последующими директивами #define и #include — стандартный прием, позволяющий избежать дублирования инфор­мации из заголовочных файлов в исходном коде проекта. Если этого не сделать, то при дублировании компилятор обычно выдает множество сообщений об ошиб­ках, связанных с многократным объявлением переменных.

 

Директива #error

Директива #error используется совместно с директивами условной компиля­ции. Встретив ее, компилятор сгенерирует сообщение об ошибке, указанное спра­ва от директивы (см. пример в предыдущем подразделе).

 

 

Форум

Программа состоит из основного модуля и  вспомогательного модуля со служебными функциями (сейчас там функции для обслуживания LED и KBD).

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

Хотелось бы все это описать один раз и в одном месте, например, в заголовочном файле, который включался бы воба исходника и объявлял в них нужные переменные и имена, а если надо что-то изменить, это делать в одном месте и не лезть в исходники. Только вот как это грамотно сделать? Если просто тупо включить хедер и туда и туда - получается ругань при компановке на повторное определние. Можно в принципе в начале вспомогательного мдуля отдефайнить какое-нибудь уникальное значение, а в хедере устроить условную компиляцию, в которой, если определено (#ifdef) - то описывать по-

нормальному, а если нет - то как extern. Но это не очень красиво, так как определения повторяются 2 раза. А вот как это делается правильно?

Обычно это делается так:

 

// module.h

#ifndef _MODULE_H_ /*если_имя_макроса_не_опреде­ленно     имя_макроса     последовательность_операторов_1*/

#define _MODULE_H_          /*#define заменяемая_последовательность     фрагмент_подстановки */                     

extern char a;               /* повторное объявление переменной a */

extern int b;                  /* повторное объявление переменной b */

void do_something(void);         /*функция «делать_кое-что» */

#endif                          /*_MODULE_H_  */

---------------------------

// module.c

#include "module.h"      /* Подключаем модуль module.h */

char a;                         /* объявление переменной a */

int b;                            /* объявление переменной b */

void do_something(void)          /* функция «делать_кое-что» */

{

  b = a;

}

---------------------------

// main.c

#include <io.h>

#include "module.h"

void main(void)

{

a=2;

do_something();                       // Вызов функции «делать_кое-что»

}

---------------------------

То есть придется написать дважды про глобальные переменные : в хедере описать экстерном, в сишнике объявить. И не надо никаких ветвлений по #ifdef. :)

 

Hosted by uCoz