Макросы в C++

Макросы в C++

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

Простой макрос определяется так: 

#define name rest of line

Когда name встречается как лексема, оно заменяется на rest of line. 

Например: 

named = name

после расширения даст: 

named = rest of line

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

Например: 

#define mac(a,b) argument1: a argument2: b

При использовании mac должно даваться две строки параметра. После расширения mac() они заменяют a и b. 

Например: 

expanded = mac(foo bar, yuk yuk)

после расширения даст 

expanded = argument1: foo bar argument2: yuk yuk

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

Вот такими макросы могут быть вполне: 

#define Case break;case

#define nl <<"\n"

#define forever for(;;)

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

Вот совершенно ненужные макросы: 

#define PI 3.141593

#define BEGIN {

#define END }

А вот примеры опасных макросов: 

#define SQUARE(a) a*a

#define INCR_xx (xx)++

#define DISP = 4

Чтобы увидеть, чем они опасны, попробуйте провести расширения в следующем примере: 

int xx = 0;                // глобальный счетчик

void f() {

  int xx = 0;            // локальная переменная

  xx = SQUARE(xx+2);     // xx = xx+2*xx+2

  INCR_xx;               // увеличивает локальный xx

  if (a-DISP==b) {       // a-= 4==b

      // ...

  }

}

Если вы вынуждены использовать макрос, при ссылке на глобальные имена используйте операцию разрешения области видимости ::  и заключайте вхождения имени параметра макроса в скобки везде, где это возможно (см. MIN выше). 

Обратите внимание на различие результатов расширения этих двух макросов: 

#define m1(a) something(a) // глубокомысленный комментарий

#define m2(a) something(a) /* глубокомысленный комментарий */

например, 

int a = m1(1)+2;

int b = m2(1)+2;

pасширяется в 

int a = something(1) // глубокомысленный комментарий+2;

int b = something(1) /* глубокомысленный комментарий */+2;

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