Программирование >>  Решение нетривиальных задач 

1 ... 31 32 33 [ 34 ] 35 36 37 ... 77


a(); \

b(); \

} else

но я думаю, что комбинация do с while (0) незначительно лучше.

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

#define swap int(x,y) \

do \

int x##y; \

x##y = x; \

x = y; \

y = x##y \

while (0)

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

swap(laurel, hardy);

препроцессор вначале подставляет аргументы обычным порядком (заменяя x на laurel, а y на hardy), давая в результате следующее имя временной переменной:

int laurel##hardy;

Затем препроцессор удаляет знаки решетки, давая int laurelhardy;

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

#define AT LEFT(this) ((this)->left child is thread ? NULL\

:(this)->left)

#ifdef DEBUG

static tnode *at left(tnode *this) { return AT LEFT(this); }



#else

# define at left(this) AT LEFT(this)

#endif

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

Таблица 1. Макросы, эквивалентные условным операторам

Этот код:

Делает то же самое, что и:

( a && f() )

if( a )

f();

( b f() )

if( !b )

f();

( z ? f() : g())

if( z )

f();

else

g();

Первые два выражения опираются на тот факт, что вычисления в выражении с использованием операций && и гарантированно осуществляются слева направо и прекращаются сразу, как только устанавливается истина или ложь. Возьмем для примера выражение a && f(). Если a ложно, то тогда не важно, что возвращает f(), так как все выражение ложно, если любой из его операндов значит ложь. Следовательно, компилятор никогда не вызовет f(), если a ложно, но он должен вызвать f(), если a истинно. То же самое применимо и к b, но здесь f() вызывается, если b, напротив, ложно.

81.1. Операция ?: не то же самое, что и оператор if/else

Последняя строка в таблице 1 относится к другому спорному вопросу. Условная операция - это простой оператор. Она используется лишь в выражении и передает значение. Условная операция является не очень привычной заменой для оператора if/else, но не менее, чем операции && или приемлемы для замены простого if. Хотя большинство людей



z && (i = j); z (i = k);

Мне довелось случайно увидеть подобное этому, но с использованием условной операции:

z ? (i = j) : (i = k) ;

Все предыдущие фрагменты в равной мере способны сбить с толку. Следующий код показывает, как надлежащим образом использовать условную операцию, и ее результат яснее (т.е. лучше), чем у равноценного оператора if/else:

i = z ? j : k ;

81.2. Помещайте тело макроса и его аргументы в круглые скобки

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

#define TWO K 1024 + 1024

что при использовании в:

10 * TWO K

расширяется до:

10* 1024 + 1024

вычисляемого как:

(10 * 1024) + 1024

Решаем эту задачу при помощи круглых скобок:

#define TWO K (1024 + 1024)

Вот сходная задача в следующем фрагменте кода:

#define SQUARE(x) (x * x)

Определено:

SQUARE(y + 1);

и не принимают во внимание замену: if( z )

i = j;

else

i = k;



1 ... 31 32 33 [ 34 ] 35 36 37 ... 77

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