- #define
- Работа
#define
Директива определения макроподстановки (макроса).
Директива может иметь один из двух форматов:
#define <идентификатор> [значение]
или
#define <идентификатор>(псевдо-параметры) <тело>
Здесь идентификатор - любой допустимый синтаксисом идентификатор, значение - любой набор символов. Псевдо-параметры - это список (через запятую) идентификаторов, используемых в качестве составной части при определении тела, представляющего собой так же любой набор символов.
Первая форма директивы получила название директивы определения символа или простого макроса, а вторая - директива определения макроса-функции (из-за внешнего сходства с определением функции).
Действие директивы в любом из форматов заключается в том, что препроцессор, встретив в тексте программы определенный директивой идентификатор, осуществляет подстановку вместо него соответствующего значения или тела, причем подстановка осуществляется именно путем ввода текстовых символов. Это, в частности, подразумевает, что в качестве идентификатора можно использовать даже ключевые слова языка Си!
Рассмотрим ряд примеров.
Пусть указаны следующие директивы:
#define D1 7
#define D2 + 5 *
#define D3 if
А далее в тексте программы эти символы используются так:
for (i = D1; i < D1 D2 3; i++)
D3 (i == 5) break;
После того, как препроцессор обработает указанные строки, будет сгенерирован следующий текст программы:
for (i = 7; i < 7 + 5 * 3; i++)
if (i == 5) break;
To есть вместо символов D1, D2 и D3 соответственно будут подставлены их значения. Смысл полученного текста лежит на совести программиста.
При объявлении макроса-функции перед тем, как осуществить замену символа в тексте программы, препроцессор осуществляет подстановку вместо псевдо-параметров их фактические значения, и лишь затем тело макроса подставляется в текст:
#define foo(x) x + 5
int k = foo(45*x);
// после обработки препроцессором заменится на
int k = 45*x + 5;
Важно понимать, что любой макрос-это именно текстовая подстановка, т.е. в отличие от настоящей функции не происходит никакой передачи параметров, вызова и т.п. - именно поэтому псевдопараметр макроса не имеет типа.
Из-за того, что подстановки осуществляются, начиная с первого символа (не пробельного) после идентификатора и до конца строки, следует быть осторожными с использованием однострочных комментариев и точки с запятой. Следующие примеры явно неверные:
#define LINE 56 // определяем константу
#define cnt(x, y) while(x[y++] != ‘ ‘);
for (i = 0; i < LINE; i ++) arr[i] = i;
count = cnt(arr, i) * 12;
В результате обработки препроцессором будет сформирован следующий текст (комментарии из текста удаляются):
for (i = 0; i < 56
count = while(arr[i++] != ‘ ‘); * 12;
B первом операторе из-за наличия однострочного комментария в строке определения макроса будет удалена важная часть, а во втором получится сразу две ошибки: во-первых, макрос - это не функция, и в итоге оператор присваивания приобретает недопустимый вид, а во-вторых, умножение на 12 окажется отделенным точкой с запятой из тела макроса от остальной части оператора, что, естественно, так же недопустимо.
В связи с этими особенностями макросов настоятельно рекомендуется придерживаться следующих правил:
1. В определении макроса, если это необходимо, использовать только комментарии вида /*...*/
2. Заключать в круглые скобки как все тело макроса, так и входящие в него псевдопараметры
3. Не завершать тело макроса точкой с запятой Примеры правильно определенных макросов:
#define LINE 56 /* числовую константу можно без скобок */
#define cnt(x,y) ( (x) * (y) ) /* скобки лишними не бывают! */
Если определяемый макрос не умещается на одной строке, допускается использовать символ переноса - обратная черта.
Допускается повторно определять один и тот же макрос в разных местах программы, это сопровождается предупреждением компилятора, но, в сущности, безопасно. Переопределенный макрос начинает действовать для строк программы, находящихся ниже его определения, а выше действует старое определение.