Вівторок, 19.03.2024, 13:10
Гость

Мішатронік

Мобільна версія | Додати у вибране  | Мій профіль | Вихід | RSS |
Меню сайту
Наше опитування
Java чи С++
Всього відповідей: 2
Статистика

Онлайн всього: 1
Гостей: 1
Користувачів: 0


Использование аргументов с #define

Во избежание ошибок при вычислении выражений параметры макроопределения необходимо заключать в скобки.

 
#define идентификатор1 (идентификатор2, . . .) строка
 

Пример:

 
#define abs(A) (((A) > 0)?(A) : -(A))
 

Каждое вхождение выражения abs(arg) в тексте программы заменяется на

 
((arg) > 0) ? (arg) : -(arg),
 

причем параметр макроопределения А заменяется на arg.

 

Пример:

 
#define nmem(P,N)\
(P) -> p_mem[N].u_long
 

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

 

Макроопределение с аргументами очень похоже на функцию, поскольку аргументы его заключены в скобки:

 
/* макроопределение с аргументами */ 
#define SQUARE(x) x*x
#define PR(x) printf("x равно %d.\n", x)
int main( )
{
 int x = 4; int z;
 z = SQUARE(x);
 PR(z);
 z = SQUARE(2);
 PR(z);
 PR(SQUARE(x));
 PR(SQUARE(x+2));
 PR(100/SQUARE(2));
 PR(SQUARE(++x));
 return 0;
}
 

Всюду, где в нашей программе появляется макроопределение SQUARE(x), оно заменяется на x*x. В отличие от наших прежних примеров, при использовании этого макроопределения мы можем совершенно свободно применять символы, отличные от x. В макроопределении ' x ' замещается символом, использованным в макровызове программы. Поэтому макроопределение SQUARE(2)замещается на 2*2. Таким образом, x действует как аргумент. Однако, аргумент макроопределения не работает - точно так же, как аргумент функции. Вот результаты выполнения программы:

 
z равно 16.
z равно 4.
SQUARE(x) равно 16.
SQUARE(x+2) равно 14. 
100/SQUARE(2) равно 100.
SQUARE(++x) равно 30.

Первые две строки очевидны. Заметим, что даже внутри двойных кавычек в определении PR переменная замещается соответствующим аргументом. Все аргументы в этом определении замещаются. Рассмотрим третью строку:

 
PR(SQUARE(x));
 

Она становится следующей строкой:

 
printf("SQUARE(x) равно %d.\n", SQUARE(x));
 

после первого этапа макрорасширения. Второе SQUARE(x) расширяется, превращаясь в x*x, а первое остается без изменения, потому что теперь оно находится внутри кавычек в операторе программы, и таким образом защищено от дальнейшего расширения. Окончательно строка программы содержит

 
printf("SQUARE(x) равно %d.\n",x*x);
 

и выводит на печать

 
SQUARE(x) равно x*x.
 

Если макроопределение включает аргумент с двойными кавычками, то аргумент будет замещаться строкой из макровызова. Но после этого он в дальнейшем не расширяется, даже если строка является еще одним макроопределением. В нашем примере переменная xстала макроопределением SQUARE(x) и осталась им. Вспомним, что x=4. Это позволяет предположить, что SQUARE(x+2) будет равно 6*6 или 36. Но напечатанный результат говорит, что получается число 14. Причина такого результата такова:препроцессор не делает вычислений. Он только замещает строку. Всюду, где наше определение указывает на xпрепроцессорподставит строку x+2.

 

Таким образом,

 
x*x становится x+2*x+2
 

Если x равно 4, то получается

 
4+2*4+2=4+8+2=14
 

Вызов функции передает значение аргумента в функцию во время выполнения программы. Макровызов передает строку аргументов в программу до ее компиляции.

 

Макроопределение или функция?

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

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

 

Выбор макроопределения приводит к увеличению объема памяти, а выбор функции - к увеличению времени работы программы. Макроопределение создает строчный код, т.е. мы получаем оператор в программе. Если макроопределение применить 20 раз, то в программу вставится 20 строк кода. Если мы используем функцию 20 раз, то у нас будет только одна копия операторов функции. Однако управление программой следует передать туда, где находится функция, а затем вернуться в вызывающую программу, а на это потребуется больше времени, чем при работе со строчными кодами. Так что думайте, что выбирать!

 

Преимущество макроопределений заключается в том, что при их использовании нам не нужно беспокоиться о типах переменных, т.к. макроопределения имеют дело с символьными строками, а не с фактическими значениями. Tак наше макроопределениеSQUARE(x) можно использовать одинаково хорошо с переменными типа int или float.

 

Запомним!

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

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

 

Включение файла: #include

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

 

assert.h - диагностика программ

 

ctype.h - преобразование и проверка символов

 

errno.h - проверка ошибок

 

float.h - работа с вещественными данными

 

limits.h - предельные значения целочисленных данных

 

locale.h - поддержка национальной среды

 

math.h - математические вычисления

 

setjump.h - возможности нелокальных переходов

 

signal.h - обработка исключительных ситуаций

 

stdarg.h - поддержка переменного числа параметров

 

stddef.h - дополнительные определения

 

stdio.h - средства ввода-вывода

 

stdlib.h - функции общего назначения (работа с памятью)

 

string.h - работа со строками символов

 

time.h - определение дат и времени

 

В конкретных реализациях количество и наименование заголовочных файлов могут быть и другими. Например, в компиляторах дляMS-DOS активно используются заголовочные файлы mem.halloc.hconio.hdos.h и другие. В компиляторах Turbo C, Borland C++ для связи с графической библиотекой применяется заголовочный файл graphics.h.

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

 
#include <имя_файла>
 

Пример:

 
#include <math.h>
 

Препроцессор заменяет эту строку содержимым файла math.h. Угловые скобки означают, что файл math.h будет взят из некоторого стандартного каталога (обычно это /usr/include ). Текущий каталог не просматривается:

 
#include "имя_файла"
 

Пример:

 
#include "ABC"
 

Препроцессор заменяет эту строку содержимым файла ABC. Так как имя файла заключено в кавычки, то поиск производится в текущем каталоге (в котором содержится основной файл исходного текста). Если в текущем каталоге данного файла нет, то поискпроизводится в каталогах, определенных именем пути в опции -l препроцессора. Если и там нет файла, то просматривается стандартный каталог.

 

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

 

В конкретных реализациях количество и наименования заголовочных файлов могут быть разными:

 
#include <stdio.h> ищет в системном каталоге
#include "my.h" ищет в текущем рабочем 
 каталоге
#include "/user/1/my.h" ищет в каталоге /user/1
 

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

 
#include "stdio.h" ищет на стандартном диске
#include <stdio.h> ищет на стандартном диске
#include "a:stdio.h" ищет на диске а
 

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

 

Некоторые файлы включены в систему, например, stdio.h, но можно создать и свой файл.

 

Форма входа
Пошук
Друзі сайту
Календар
«  Березень 2024  »
ПнВтСрЧтПтСбНд
    123
45678910
11121314151617
18192021222324
25262728293031

Єдина Країна! Единая Страна!