ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Среда
8 мая
53255 Топик полностью
ReAl (08.03.2006 20:37, просмотров: 1) ответил Romario на ok
Попытался отрешиться от твоего кода и прикинуть - а как бы я решал эту задачу. Сразу скажу - если это не противоречит логике задачи - я по старой привычке предпочитаю *--ptr с точки "за концом массива" и *ptr++ от его начала. Как-то сложилось впечатление, что в большинстве случаев (архитектур) *--ptr и *ptr-- либо эквивалентны по коду, либо *--ptr лучше. Если честно, то врядли я использовал бы этот трюк c переплетёнными switch и do-while в реальной программе - за исключением вылизывания под конкретный проц+компилятор как один из вариантов. Если бы мне надо было решить эту задачу быстро, "а там посмотрим - надо ли что-то улучшать", то я её решил бы в лоб (подчёркиваю, что так, с 16-битной рабочей переменной, я писал бы и для восьмибитника):
#include 

void 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()
А теперь - главный итог лабораторной работы. Число байт, занятое подпрограммой, время в циклах тела основного цикла, байт на стеке (push/pop регистров). Всё - WinAVR-20060125, опция -mmcu=atmega8 -O2
вариант		байт	циклов	стек
исходный	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-го я бы в критичном случае эту подпрограмму сразу бы делал на ассемблере. А в некритичном и так сошло бы.