Если мы возьмем реализацию из статьи в Википедии, вы ссылаетесь ...
send(to, from, count)
register short *to, *from;
register count;
{
register n=(count+7)/8;
switch(count%8){
case 0: do{ *to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
}while(--n>0);
}
}
... и замените «высокоуровневый» цикл do
/ while
на уровень сборки if
/ goto
, чтобы компилятор действительно уменьшал его до ...
send(to, from, count)
register short *to, *from;
register count;
{
register n=(count+7)/8;
switch(count%8){
case 0: do_label: *to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
if (--n>0) goto do_label;
}
}
... это может помочь вам понять, что - в этом случае, когда область действия do / while не вводит локальные переменные, - на самом деле нет ничего большего, чем переход к случаю 0, который обходит переключатель и, следовательно, необходимость оценки количества% 8 (% - довольно дорогая операция в схеме вещей).
Надеюсь, что это помогает щелкнуть, но не может ...? : -)
Почему Дафф использовал 8? Это может быть 16, 65536 или что-то еще. Из-за размера кода? Есть ли другая причина? Например, преимущества кэширования или конвейеризации.
Просто случай убывающей отдачи. Необходимость выполнения проверки --n > 0
и перехода после каждых 8 копий данных не является большой процентной нагрузкой, но размер кода (как в исходном, так и в скомпилированном коде в кеше) все еще довольно узок. Может быть, это будет 90 или 95% работы против накладных расходов, что, очевидно, было достаточно хорошо. Кроме того, чтобы проиллюстрировать концепцию и поделиться ею с другими, Том Дафф, возможно, предпочел, чтобы она соответствовала коду, типичному для терминала 80x25, а не странице или 10.