Исключение повторного включения заголовочных файлов — КиберПедия 

История развития хранилищ для нефти: Первые склады нефти появились в XVII веке. Они представляли собой землянные ямы-амбара глубиной 4…5 м...

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

Исключение повторного включения заголовочных файлов

2019-10-30 165
Исключение повторного включения заголовочных файлов 0.00 из 5.00 0 оценок
Заказать работу

Макроопределение может состоять только из имени макроса, например

# define MY_ H

После такой директивы считается, что макрос определен, но включать в текст программы макрокоманду MY_H нельзя – невозможно выполнить подстановку. Но имя макроса можно использовать в директивах условной трансляции, имеющих следующую структуру:

# ifndef <имя макроса>

<строки, которые включаются в компилируемый текст исходного модуля,

если макрос определен и исключаются из него, если макрос не определен>

# endif

Вместо условия #ifndef можно применять также противоположное ему условие # ifdef

Кроме директив #ifdef или #ifndef условная трансляция может задаваться служебным словом #if, после которого следует константное логическое выражение. В частности, директива

#if defined будет работать также, как #ifdef, а

#if!defined – также, как #ifndef.

Показанные выше директивы условной трансляции должны использоваться в любом заголовочном файле, чтобы не допустить его повторного включения в исходный модуль. Пусть у нас есть заголовочный файл My.h, в котором объявлены константа и прототип функции

const double _2Pi=2*3.14159;

void Func(int, int);

Если мы по ошибке включим его в программу дважды:

#include “My.h”

#include “My.h”

то получим сообщение error C2370: '_2 Pi': redefinition; different storage class о том, что в программе объявлены две константы с одинаковым именем. Вероятность возникновения такой ошибки достаточно велика из-за того, что включаемый файл допускает вложение в него других включаемых файлов. Если кроме My.h у нас создан еще List.h, внутри которого есть строка #include “My.h”, то уже вполне возможен повторный вызов My.h двумя строками

#include “My.h”

#include “List.h”

Eсловная трансляция позволяет исключить повторное включение в текст программы файла My_h:

#ifndef MY_H

#define MY_H

const double _2Pi=2*3.14159;

void Func(int, int);

# endif

При первом включении в текст программы файла My_h макрос MY_H еще не определен и компилятор обрабатывает строки файла. При втором, ниже по тексту, включении макрос определен и весь текст от #ifndef MY_H до #endif исключается из процесса компиляции.

Во время компиляции программы можно узнать, как она компилируется, как программа на языке Си или С++, или какая при компиляции была установлена модель памяти. Для этого можно проверить системные макросы: # ifdef _ cplusplus, # ifdef __ SMALL__ и пр.

Замечание. Описанными директивами можно проверить только наличие в программе макроопределений. Но проверить, объявлена ли переменная или константа с заданным именем нельзя. Включение в программу следующего фрагмента

Int   MMM;

# ifdef MMM

int MM 1=3;

# endif

не приведет к объявлению переменной MM1, так как в программе нет макроса с именем MMM.

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

В качестве примера применения этих возможностей рассмотрим, как в С++ для MS DOS определена константа NULL.

Указатели в С++, работающем в среде DOS, могут состоять из двух или четырех байтов в зависимости от модели памяти. Поэтому, например, в модели HUGE для совместимости с указателем константа NULL должна быть длинным целым, а в модели SMALL – словом. Для настройки на модель памяти эта константа в среде Borland определена в файле NULL.h следующим образом

#ifndef NULL

#if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__)

# define NULL 0 Если модель крохотная, малая или средняя NULL – это слово.

# else

# define NULL 0 L Для других моделей это двойное слово.

# endif    Это #endif для вложенной директивы #if defined.

# endif       Это #endif для директивы #ifndef NULL.

Итак, если константа NULL уже определена раньше, препроцессор ничего не вставит в текст программы, если нет, он вставит строку

define NULL 0

или строку

define NULL 0L.

В результате такого определения в языке С++ появляется некоторая нелогичность, которую не очень рекламируют: указатели не совместимы с целыми, но число ноль можно записать в указатель, а значение указателя NULL – в переменную целого типа.

Но сделанное для нуля исключение того стоит, в результате все синтаксические конструкции работают с пустым указателем, как с обычным нулем. Вспомним, как мы проверяли, открылся ли файл:

if ((f = fopen (“ txt. txt ”,” w ”))! = NULL) …

потому что в скобках должно быть целое число. Теперь ясно, что можно было проверять и значение указателя f:

if (f=fopen (“txt.txt”,”w”))...

При знакомстве со списками мы видели, как это свойство пустого указателя позволяет просматривать списки циклом for.

В среде Windows указатели всегда 32-битные, используется только одна модель памяти, поэтому аналогичное определение в файле Windef.h выглядит значительно проще:

#ifndef NULL

#ifdef __cplusplus

#define NULL 0

#else

#define NULL ((void *)0)

#endif

#endif

Директивы условной трансляции позволяют также выбрать для компиляции один из нескольких вариантов текста при помощи следующей конструкции

# if <условие 1>

<Текст, используемый при выполнении условия 1>

# elif < условие 2>

< Текст, используемый при выполнении условия 2>

# elif < условие n>

< Текст, используемый при выполнении условия n >

# else

< Этот текст компилятор использует, если не выполнено ни дно из условий>

# endif

Следует обратить внимание на отличие условной компиляции от условного оператора:

– в условном операторе обе ветви присутствуют в исполняемом файле, но выполняется только одна;

– при условной компиляции в исполнительном модуле только одна выбранная ветвь. Это уменьшает размер файла и увеличивает скорость, так как во время работы программы не выполняется проверка условий – они проверены на этапе компиляции. 

 

 


Поделиться с друзьями:

Состав сооружений: решетки и песколовки: Решетки – это первое устройство в схеме очистных сооружений. Они представляют...

Индивидуальные и групповые автопоилки: для животных. Схемы и конструкции...

Опора деревянной одностоечной и способы укрепление угловых опор: Опоры ВЛ - конструкции, предназначен­ные для поддерживания проводов на необходимой высоте над землей, водой...

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



© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!

0.016 с.