Int main(void)
{
int ultra = 0, super = 0;
while (super < 5)
{
super++;
++ultra;
printf("super = %d, ultra = %d \n", super, ultra);
}
return 0;
}
Выполнение программы add one.c генерирует следующий вывод:
super = 1, ultra = 1 super = 2, ultra = 2 super = 3, ultra = 3 super = 4, ultra = 4 super = 5, ultra = 5
Программа одновременно дважды просчитала до пяти. Тот же результат можно было бы получить, заменив две операции инкремента следующими операторами присваивания:
super = super + 1; ultra = ultra + 1 ;
Это достаточно простые операторы. Зачем создавать еще одно сокращение, не говоря уже о двух? Одна из причин заключается в том, что компактная форма позволяет улучшить читабельность и упростить программы. Данные операции придают программам изящество и элегантность, радуя глаз. Например, часть программы shoes2.c из листинга 5.2 можно переписать так:
shoe = 3.0;
while (shoe < 18.5)
{
foot = SCALE * size + ADJUST;
printf("% 10.1f %20.2f дюймов\n", shoe, foot);
++shoe;
}
Тем не менее, вы по-прежнему не до конца задействовали преимущества операции инкремента. Фрагмент программы можно еще больше сократить, как показано ниже:
shoe = 2.0;
while (++shoe < 18.5)
{
foot = SCALE*shoe + ADJUST;
printf("%10.1f %20.2f дюймов\n", shoe, foot);
}
Здесь процесс инкрементирования и сравнения из цикла while объединены в одно выражение. Конструкции такого типа настолько часто встречаются в программах на С, что заслуживают более пристального внимания.
Во-первых, как работает такая конструкция? Все довольно просто. Значение переменной shoe увеличивается на 1, а затем сравнивается с 18.5. Если оно меньше 18.5, то операторы, заключенные в фигурные скобки, выполняются один раз. Затем shoe снова увеличивается на 1 и цикл продолжается до тех пор, пока значение shoe не станет достаточно большим. Чтобы скомпенсировать инкремент переменной shoe, выполненный перед первым вычислением значения переменной foot, мы уменьшили начальное значение shoe с 3.0 до 2.0 (рис. 5.4).
Во-вторых, в чем преимущества такого подхода? Программа становится компактной. Но более важно то, что при этом объединяются в одном месте два процесса, которые управляют циклом. Первичным процессом является проверка того, продолжать ли выполнение цикла? В данном случае проверка заключается в выяснении, меньше ли значение переменной size, чем 18 . 5. Вторичный процесс изменяет значение проверяемого объекта; в данном случае размер обуви увеличивается на единицу.
Предположим, что вы забыли изменить размер обуви. Тогда значение переменной shoe всегда будет меньше 18.5, и цикл никогда не завершится. Вошедший в бесконечный цикл компьютер будет выводить одну и ту же строку. В конце концов, вы потеряете интерес к выводу и будете вынуждены как-то прервать выполнение программы. Проверка условия и изменение параметра цикла в одном месте, а не в разных, помогает помнить о необходимости изменить значение параметра цикла.
Недостаток объединения двух операций в одно выражение заключается в том, что это затрудняет понимание кода и увеличивает вероятность внесения ошибок.
Еще одно достоинство операции инкремента состоит в том, что она приводит к генерации несколько более эффективного кода на машинном языке по причине своего подобия действительным инструкциям машинного языка. Тем не менее, по мере улучшения компиляторов С поставщиками программного обеспечения это преимущество постепенно исчезает. Интеллектуальный компилятор способен распознать, что операцию х = х + 1 можно трактовать как ++х.
Наконец, эти операции обладают дополнительной характеристикой, которая может оказаться полезной в ряде тонких ситуаций. Чтобы выяснить, о чем идет речь, попробуйте запустить программу из листинга 5.11.
Листинг 5.11. Программа post_pre.c
/* post_pre.c -- постфиксная и префиксная формы*/
#include <stdio.h>
