Программирование >>  Полиморфизм без виртуальных функций в с++ 

1 ... 135 136 137 [ 138 ] 139 140 141 ... 144


Глава 18. Препроцессор С

Срр должен быть разрушен.

Почти Катон Старший

Среди средств, приемов и идей, которые С++ унаследовал от С, был и препроцессор Срр. Ориентация препроцессора на обработку файлов принципиально не согласуется с языком программирования, в основе которого лежат области действия, типы и интерфейсы. Рассмотрим на первый взгляд безобидный фрагмент:

finclude <st:dio.h>

extern double sqrt (double) ,-

main() {

printf( Квадратный корень из 2 равен %g\n , sqrt(2)), fflush(stdout); return(0);

Очевидно, что он печатает следующее: Квадратный корень из 2 равен 1.41421

Это кажется вполне разумным, но я откомпилировал строку таким образом:

сс -Dsqrt=rand -Dreturn=abort

после чего было напечатано

Квадратный корень из 2 равен 7.82997е+28 abort - core dumped

И программа завершилась с дампом памяти.

Пожалуй, это чересчур необычный пример и вряд ли вы станете использовать флаги компилятора для определения макросов Срр, но суть дела от этого не меняется. Макроопределения могут быть скрыты в среде разработки, в директивах компилятора и в заголовочных файлах. Макроподстановки игнорируют границы областей действия и могут даже изменять структуру области действия, вставляя фигурные скобки, кавычки и т.д. Это позволяет программисту менять текст, видимый компилятору, не трогая ни единой строки кода. Конечно, иногда даже самые экстремальные способы использования Срр могут оказаться полезными, но его средства до такой степени не структурированы, что являются источниками постоянных трудностей для программистов, отвечающих за разработку, сопровождение



Директивы #if, #11пеи #undef тоже важны, ио в контексте данного обсуждения значения не и.меют.

и перенос кода на другие платформы, а также для авторов инструментальных средств.

Быть может, худшей из всех особенностей Срр является то, что он сдерживал создание сред программирования на С. Невозможность управлять работой Срр, в основе которого лежит посимвольный разбор файла, делает нетривиальные инструментальные средства для С и C-t-i- более громоздкими, медленными и менее изящными, чем они .могли бы быть.

Срр нельзя даже назвать хорошим .макропроцессором. Поэтому я поставил себе целью изжить Срр. Но задача оказалась труднее, че.м представлялось вначале. Срр, возможно, и неудачен, но трудно найти ему лучше структурированную и более эффективную за,мену.

У препроцессора С есть четыре основных директивы

□ tinclude копирует исходный текст из другого файла;

□ #def ine определяет макрос (с аргументами или без);

□ #if def включает последующие строки в зависимости от условия;

□ #pragma влияет на поведение ко.мпилятора способом, зависящим от реализации.

Эти директивы применяются для решения различных задач программирования:

#include

□ сделать доступным определение интерфейса;

□ составить исходный текст из различных частей.

#define

□ определить:

- си.мволические константы;

- открытые подпрогра.ммы;

- обобщенные подпрограммы;

- обобщенные типы;

□ переименовать;

□ связать строки;

□ определить специализированный синтаксис;

□ сделать общую .макрообработку.

#ifdef

□ осуществить контроль версий;

□ произвести ко.мментироваиие кода.

#pragma

□ осуществить управление раз.меихением структур данных в памяти;

□ информировать компилятор о необычном потоке управления.

Все эти задачи решаются с по.мощью Срр довольно неудачно, с использованием непрямых методов, но тем не менее эффективно, и зачастую для практических



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

В С++ имеются альтернативы для большинства основных применений директивы #def ine:

□ модификатор const для определения констант (см. раздел 3.8);

□ модификатор inline для открытых подпрограмм (см. раздел 2.4.1);

□ шаблоны для функций, параметризованных типами (см. раздел 15.6);

□ шаблоны для параметризованных типов (см. раздел 15.3);

□ пространства имен для обобщения именования (см. главу 17).

Альтернативы директиве #include в С++ нет, хотя пространства имен предоставляют механизм областей действия, который поддерживает композицию таким образом, что поведение #include становится более структурированным.

Я предлагал добавить директиву include в сам язык С++ в качестве замены одноименной директиве Срр. Директива include отличалась бы от препроцессорной следующим:

□ если файл включен дважды, то второй include игнорируется. Это устраняет часто встречающуюся проблему, которая сейчас решается искусственно и неэффективно с помощью директив #def ine и #ifdef;

□ макрос, определенный вне включенного с помощью include текста, не расширяется внутри этого текста, что обеспечивает защиту информации от случайного воздействия макросов;

□ макрос, определенный внутри включенного с помощью include текста, не расширяется в тексте, который обрабатывается после включенного. Тем самым гарантируется, что макросы во включенном тексте не вводят зависимость от порядка в ту единицу трансляции, которая включает файл. Также это защищает от сюрпризов, которые могут преподнести макросы.

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

Остаются директивы # i f def и #pragma. Без последней можно вполне обойтись, поскольку я ни разу еще не встречал понравившейся мне прагмы. Слишком часто #pragma используется для того, чтобы украдкой под.менить семантику языка и внедрить чрезмерно специализированные расширения, к тому же с нелепым синтаксисом. Для директивы # if def у нас пока нет подходящей замены. В частности, использование предложений if и константных выражений - это неполное решение. Например:

const с = 1; . . .



1 ... 135 136 137 [ 138 ] 139 140 141 ... 144

© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки.
Яндекс.Метрика