Макроподстановки средствами препроцессора



 

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

С помощью директивы #define идентификатор строка_замещения можно вводить макроопределения, в которых строка замещения фиксирована. Большими возможностями обладает макроопределение с параметрами:

#define имя (список_параметров) строка_замещения

Здесь имя – это имя макроса (идентификатор), список_параметров – список разделенных запятыми идентификаторов.

 

//пример 1

#define max(a,b) (a<b?b:a)//макроопределение

…..

max(x,y)// заменяется выражением (x<y?y:x)

max(z,4)// заменяется выражением (z<4?4:z)

 

 

//пример 2

#define ABS(x) (x<0?-(x):x)//макроопределение

….

ABS(E-Z)// заменяется выражением (E-Z<0?-(E-Z):E-Z)

 

 

Отличия макроса от функции:

1. Определение функции присутствует в программе в одном экземпляре, коды формируемые макросом вставляются в программу столько раз, сколько используется макрос. В этом отношении макросы похожи на inline функции, но подстановка для макроса выполняется всегда.

2. Функция определена для данных того типа, который указан в спецификации и возвращает значения только одного конкретного типа. Макрос пригоден для обработки параметров любого типа. Тип полученного значения зависит от типов параметров и самих выражений. В примерах 1 и 2 в качестве параметров могут использоваться любые целочисленные или вещественные типы.

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

 

#define max(a,b) (a<b?b:a)

#define t(e) e*3

#define PRN(c) cout<<”\n”<<#c<<” равно ”;cout<<c;

#define E x*x

#include<iostream.h>

void main()

{

int x=2;

PRN(max(++x,++x);

PRN(t(x));

PRN(t(x+x));

PRN(t(x+x)/3);

PRN(E);

}

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

Таблица 4. Примеры подстановок параметров макроса

PRN(max(++x,++x);   1-ая подстановка cout<<”\n”<<”max(++x,++x)”<<” равно ”;cout<< max(++x,++x); 2-ая подстановка cout<<”\n”<<”max(++x,++x)”<<” равно ”;cout<<(++x<++x?++x:++x);//т. е. х увеличится на 3 (=5)
PRN(t(x));   1-ая подстановка cout<<”\n”<<”t(x)”<<” равно ”;cout<< t(x) 2-ая подстановка cout<<”\n”<<”t(x)”<<” равно ”;cout<<x*3;//x=5, результат 15
PRN(t(x+x));   1-ая подстановка cout<<”\n”<<”t(x+x)”<<” равно ”;cout<< t(x+x) 2-ая подстановка cout<<”\n”<<”t(x+x)”<<” равно ”;cout<<(x+x)*3;//x=5, результат 30
PRN(t(x+x)/3);   1-ая подстановка cout<<”\n”<<”t(x+x)”<<” равно ”;cout<< t(x+x)/3 2-ая подстановка cout<<”\n”<<”t(x+x)”<<” равно ”;cout<<(x+x)*3/3;//результат (5+5)*3/3=10
PRN(E);   1-ая подстановка cout<<”\n”<<”E”<<” равно ”;cout<<E; 2-ая подстановка cout<<”\n”<<”E”<<” равно ”;cout<<x*x;// результат25  

Результаты:

max(++x,++x) равно 5

t(x) равно 15

t(x+х) равно 20

t(x+х)/3 равно 10

Е равно 25

 

Технология создания программ

 

Проектирование программы

 

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

Этапы создания программы:

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

· описание исходных данных и результатов;

·  описание задачи, реализуемой программой;

·  способ обращения к программе;

·  описание возможных аварийных ситуаций и ошибок пользователя.

2. Разработка внутренних структур данных. Большинство алгоритмов зависит от способа организации данных (статические или динамические, массивы, списки или деревья и т. п.).

3. Проектирование программы, которое заключается в определении общей структуры и способов взаимодействия модулей. На данном этапе может применяться технология нисходящего проектирования, при котором задачу разбивают на подзадачи меньшей сложности. На этом этапе очень важной является спецификация интерфейсов, т. е. способов взаимодействия подзадач. Для каждой подзадачи составляется внешняя спецификация, аналогичная п. 1. На этом же этапе решаются вопросы разбиения программы на модули, взаимодействие этих модулей должно быть минимальным. На более низкий уровень проектирования переходят только после окончания проектирования верхнего уровня. Алгоритмы для модулей записывают в обобщенной форме (словесная запись, блок-схемы). Проектировать программу надо таким образом, чтобы в нее достаточно легко можно было внести изменения. Процесс проектирования является итерационным, т. к. невозможно учесть все детали с первого раза.

4. Структурное программирование. Процесс программирования также должен быть организован сверху вниз: сначала кодируются модули самого верхнего уровня и составляются тестовые примеры для их отладки, на месте модулей, которые еще не написаны, ставятся, так называемые «заглушки». Заглушки выдают сообщение о том, что им передано управление, а затем снова возвращают управление в вызывающую программу. При программировании следует отделять интерфейс модуля от его реализации и ограничивать доступ к ненужной информации. Этапы проектирования и программирования совмещены во времени: сначала проектируется и кодируется верхний уровень, затем – следующий и т. д. Такая стратегия применяется, т. к. в процессе кодирования может возникнуть необходимость внести изменения, которые потом отразятся на модулях нижнего уровня.

5. Нисходящее тестирование. Проектирование и программирование сопровождаются тестированием. Цель процесса тестирования – определение наличия ошибки, нахождение места ошибки, ее причины и соответствующие изменения программы – исправление. Тест – это набор исходных данных, для которых заранее известен результат. Тест, выявивший ошибку, считается успешным. Процесс исправления ошибок в программе называется отладкой, исправляются ошибки обнаруженные при тестировании. Отладка программы заканчивается, когда достаточное количество тестов выполнилось неуспешно, т. е. программа на них выдала правильные результаты.

Цель тестирования показать, что программа работает правильно и удовлетворяет всем проектным спецификациям. Чем больше ошибок обнаружено на начальных стадиях тестирования, тем меньше их остается в программе. Чем меньше ошибок осталось в программе, тем сложнее искать каждую из этих ошибок.

Идея нисходящего тестирования заключается в том, что к тестированию программы надо приступать еще до того, как завершено ее проектирование. Только после того как проверен и отлажен один уровень программы, можно приступать к программированию и тестированию следующего уровня.

Для исчерпывающего тестирования рекомендуется проверить:

· каждую ветвь алгоритма;

· граничные условия;

· ошибочные исходные данные.

 


Дата добавления: 2018-04-04; просмотров: 316;