Попытался отрешиться от твоего кода и прикинуть - а как бы я решал эту задачу. Сразу скажу - если это не противоречит логике задачи - я по старой привычке предпочитаю *--ptr с точки "за концом массива" и *ptr++ от его начала. Как-то сложилось впечатление, что в большинстве случаев (архитектур) *--ptr и *ptr-- либо эквивалентны по коду, либо *--ptr лучше.
Если честно, то врядли я использовал бы этот трюк c переплетёнными switch и do-while в реальной программе - за исключением вылизывания под конкретный проц+компилятор как один из вариантов. Если бы мне надо было решить эту задачу быстро, "а там посмотрим - надо ли что-то улучшать", то я её решил бы в лоб (подчёркиваю, что так, с 16-битной рабочей переменной, я писал бы и для восьмибитника):
#includeА теперь - главный итог лабораторной работы. Число байт, занятое подпрограммой, время в циклах тела основного цикла, байт на стеке (push/pop регистров). Всё - WinAVR-20060125, опция -mmcu=atmega8 -O2void UnPack7bData(uint8_t InBuf[], uint16_t sz) { uint8_t *src; uint8_t *dst; uint16_t cycles; union { uint16_t w; uint8_t b[2]; } u; cycles = sz >> 3; // floor(sz/8) число ПОЛНЫХ групп из 8 байт dst = InBuf + sz; // указываем ЗА последним байтом, преддекремент при занесении /* каждый байт "недобирает" один бит, поэтому чтобы взять байт буфера, в котором заканчивается искомый, надо от конца отступить floor(sz/8) байт */ src = dst - (sz >> 3) - 1; // dst было ЗА нужным байтом // "хвост" из неполной группы switch( sz & 0x07) { case 7: // src -> 5:--gggggg 6:g------- u.b[0] = *src; u.b[1] = *--src; *--dst = u.w >> 7; case 6: // src -> 4:---fffff 5:ff------ u.b[0] = *src; u.b[1] = *--src; *--dst = u.w >> 6; case 5: // src -> 3:----eeee 4:eee----- u.b[0] = *src; u.b[1] = *--src; *--dst = u.w >> 5; case 4: // src -> 2:-----ddd 3:dddd---- u.b[0] = *src; u.b[1] = *--src; *--dst = u.w >> 4; case 3: // src -> 1:------cc 2:ccccc--- u.b[0] = *src; u.b[1] = *--src; *--dst = u.w >> 3; case 2: // src -> 0:-------b 1:bbbbbb-- u.b[0] = *src; u.b[1] = *--src; *--dst = u.w >> 2; case 1: // src -> 0:aaaaaaa- *--dst = *src >> 1; --src; } // "полные" группы байт - соответствует полному телу switch + перед ним для байта 0 (8) while(cycles--) { // src -> 6:-hhhhhhh *--dst = *src & 0x7f; // src -> 5:--gggggg 6:g------- u.b[0] = *src; u.b[1] = *--src; *--dst = u.w >> 7; // src -> 4:---fffff 5:ff------ u.b[0] = *src; u.b[1] = *--src; *--dst = u.w >> 6; // src -> 3:----eeee 4:eee----- u.b[0] = *src; u.b[1] = *--src; *--dst = u.w >> 5; // src -> 2:-----ddd 3:dddd---- u.b[0] = *src; u.b[1] = *--src; *--dst = u.w >> 4; // src -> 1:------cc 2:ccccc--- u.b[0] = *src; u.b[1] = *--src; *--dst = u.w >> 3; // src -> 0:-------b 1:bbbbbb-- u.b[0] = *src; u.b[1] = *--src; *--dst = u.w >> 2; // src -> 0:aaaaaaa- *--dst = *src >> 1; --src; } } // UnPack7bData()
вариант байт циклов стек исходный 336 150 2 в лоб 265 106 0Для "лобового" варианта компилятор (avr-gcc и mingw32) сам догадался переходы switch всунуть на тело цикла, причём сделал это avr-gcc - "деревом", разделив сначала на больше/меньше 4 что в итоге на малых длинах статичтически может дать выигрыш в скорости по сравнению с цепочечными if() mingw32 - табличкой ссылок и косвенным jmp Итого... Прошу прощения у публики - кроме avr-gcc и mingw ничего под рукой нет, но для этих двух вышло "а нафига вручную байты гонять влево-вправо и вручную их сводить да с goto "оптимизировать", если это НИЧЕГО не даёт? Времена не те". А, пардон, Keil6.20... Да, "в лоб" (указатели сделаны idata) дало 446 байт вместо 288... switch сделан отделльн_м кодом. Но для 51-го я бы в критичном случае эту подпрограмму сразу бы делал на ассемблере. А в некритичном и так сошло бы.
-
- Пардон! Ошибочка вышла - для исходного подсчёты были не для меги8, а для classic AVR. Правильная табличка ReAl(164 знак., 08.03.2006 20:57, )