Страница 1 из 2
помогите оптимизировать код по размеру
Добавлено: Вт сен 02, 2014 12:51:28
ESWANT
Нужно написать функцию для преобразования байта в строку
например a=5 str='5' a=255 str='255'
причем иногда нужно доводить длину строки до 2 или 3-х символов требуемого размера дополняя слева нулями
например a=5 str='05' либо a=27 str='027'
первый вариант - две разные функци для фиксированных длин строк
если дополнять нулями не нужно то использую просто sprintf:
Код: Выделить всё
void Byte_To_ASCII_BCD_2 (byte b, unsigned char *str)
{
unsigned char buf[4]; // '2' '5' '5' '\0'
sprintf (buf,"%u",b);
if ((strlen(buf)==0)|(strlen(buf)==3)) {*str='0'; str=str+1;*str='0'; }//этот случай если sprintf выдаст пустую строку (хотя такого быть не должно так как даже на ноль должно быть '0'
if (strlen(buf)==1) {*str='0'; str=str+1;*str=buf[0]; }
if (strlen(buf)==2) {*str=buf[0]; str=str+1;*str=buf[1]; }
str=str+1;*str='\0';
}//proc
void Byte_To_ASCII_BCD_3 (byte b, unsigned char *str)
{
unsigned char buf[4]; // '2' '5' '5' '\0'
sprintf (buf,"%u",b);
if (strlen(buf)==0) {*str='0'; str=str+1;*str='0'; str=str+1;*str='0'; }//этот случай если sprintf выдаст пустую строку (хотя такого быть не должно так как даже на ноль должно быть '0'
if (strlen(buf)==1) {*str='0'; str=str+1;*str='0'; str=str+1;*str=buf[0]; }
if (strlen(buf)==2) {*str='0'; str=str+1;*str=buf[0]; str=str+1;*str=buf[1]; }
if (strlen(buf)==3) {*str=buf[0]; str=str+1;*str=buf[1]; str=str+1;*str=buf[2]; }
str=str+1;*str='\0';
}//proc
и второй вариант - решил отказаться то библиотечной sprintf
а код получился еще больше
честно говоря я его еще и не проверял - может он и не рабочий
Код: Выделить всё
//превращает байт в строку, поэтому для str достаточно 4 байта размера
//f- 0-без ведущих нулей
// 1-3 - обязательная длина (добавлять ведущие нули)
void ByteToStr(byte f,byte b, unsigned char *str)
{
byte sotni,desatki,edinici;
*str = _T('\0');
sotni = b/100; //255/100=2 5/100 = 0
desatki = ( b - (sotni*100) ) / 10;// (255-(2*100)) / 10 =5 5-(0*100) /10 = 0
edinici = ( b - (sotni*100) - (desatki*10) ) % 10; //( 255 - (2*100) - (5*10) ) % 10;
//для случая без ведущих нулей
if ( (f==3) | ( (f==0)&(sotni!=0) ) )
{
*str = sotni+0x30; str=str+1;
*str = desatki+0x30; str=str+1;
*str = edinici+0x30; str=str+1;
*str = _T('\0');
return;
}
//для случая без ведущих нулей
if ( (f==2) | ( (f==0)&(sotni==0)&(desatki!=0) ) )
{
*str = desatki+0x30; str=str+1;
*str = edinici+0x30; str=str+1;
*str = _T('\0');
return;
}
//для случая без ведущих нулей
if ( (f==1) | ( (f==0)&(sotni==0)&(desatki==0)&(edinici!=0) ) )
{
*str = edinici+0x30; str=str+1;
*str = _T('\0');
return;
}
//если число ноль то
if ( (f==0)&(sotni==0)&(desatki==0)&(edinici==0) )
{
*str=_T('0'); str=str+1;
*str = _T('\0');
}
}//proc
Что посоветуете?
Re: помогите оптимизировать код по размеру
Добавлено: Вт сен 02, 2014 12:56:27
Gisteresis
Посоветую попробовать сделать массив символов так, чтобы указатель совпадал с символом. {'0','1','2','3','4'...'9'}
Тогда обращаясь к массиву мы автоматически конвертируем цифру в символ и убирается куча ифов, которые кстати лучше было бы оформить через свич.
Кроме того можно попробовать попросить компилятор оптимизировать по размеру.
Re: помогите оптимизировать код по размеру
Добавлено: Вт сен 02, 2014 13:27:24
ESWANT
Не понял
Саму цифру в символ я конвертирую прибавляя 0x30 и все
Re: помогите оптимизировать код по размеру
Добавлено: Вт сен 02, 2014 13:43:49
Gisteresis
ESWANT писал(а):Саму цифру в символ я конвертирую прибавляя 0x30 и все
Хм... это лучше предложенного мной. Не подумал сразу.
Можно вместо ввода длины, определять ее в коде. Если число больше 9 но меньше 100 ясно, что символов 2. для остальных вариантов нужна всего одна проверка.
Код это не уменьшит, но можно сделать удобнее применени этой функции. 1 параметр тогда ненужно вводить.
Тогда такая вот идея.
Можно попробовать ифы заменить на цикл. Нужно создать массив на 3 байта и записать туда единицы, десятки, сотни, прогоняем в цикле и компонуем строку. Тогда бы эти ифы ужались бы в общий код.
Re: помогите оптимизировать код по размеру
Добавлено: Вт сен 02, 2014 14:52:58
ARV
Код: Выделить всё
#include <string.h>
#include <stdlib.h>
// предельное количество знаков в строке
#define MAXLEN 3
void byte_to_str(char s[], unsigned char fill, unsigned char byte){
unsigned char i, len;
itoa(byte,s,10); // получили 10-е число в виде строки
if(!fill) return; // если не надо добавлять нули слева - конец работы
len = strlen(s); // вычислили длину строки
memmove(s+MAXLEN-len, s, len); // передвинули символы в конец строки
s[MAXLEN] = 0; // поставили терминатор в конец строки
// в цикле дополняем нулями слева полученное число
while(MAXLEN-len){
s[MAXLEN-len-1] = '0';
len++;
}
}
как-то так...
Re: помогите оптимизировать код по размеру
Добавлено: Вт сен 02, 2014 14:58:30
ESWANT
Gisteresis писал(а):ESWANT писал(а):Саму цифру в символ я конвертирую прибавляя 0x30 и все
Тогда такая вот идея.
Можно попробовать ифы заменить на цикл. Нужно создать массив на 3 байта и записать туда единицы, десятки, сотни, прогоняем в цикле и компонуем строку. Тогда бы эти ифы ужались бы в общий код.
Вот что получилось
Код: Выделить всё
void ByteToStr(byte f,byte b, unsigned char *str)
{
byte m[3];//под числа разрядов
//[0]-единицы
//[1]-десятки
//[2]-сотни
byte begin;
m[2] = b/100; //СОТНИ 255/100=2 5/100 = 0
m[1] = ( b - (m[2]*100) ) / 10; //ДЕСЯТКИ (255-(2*100)) / 10 =5 5-(0*100) /10 = 0
m[0] = ( b - (m[2]*100) - (m[1]*10) ) % 10; //ЕДИНИЦЫ( 255 - (2*100) - (5*10) ) % 10;
if (f) begin=(f-1);//начинаем от требуемого разряда
else begin =2;//если не нужны ведущие нули то проверяем с сотен и до единиц
*str = _T('\0');//ноль используем как флаг что ничего в строку еще не добавили, чтобы пропускать только ведущие нули а если внутри ноль то его добавлять строку
//поэтому гарантированно обнулим
for (i=begin;i>=0;i--)
{
ИЛИ строка без ведущих нулей нужна И уже есть первый символ
if( (f) | //если указан фиксированный размер ИЛИ
//без вед.нулей не ноль или ноль и не первый
( (f==0) & ( (m[i]) | ((m[i]==0)&(*str)) ) )
)
{
*str=m[i]+0x30;
str++;
}
}//for
*str = _T('\0');//закончим строку
}//proc
получается просто если бы не надо предусматривать вариант без ведущих нулей
может оптимальнее две функции сделать?
одна для фиксированных длин строк
а другая для - без ведущих нулей
Re: помогите оптимизировать код по размеру
Добавлено: Вт сен 02, 2014 15:04:02
Gisteresis
Так а по весу то стало меньше?
Ну если использовать обе функции в программе то на обе нужно место, поэтому решайте сами воспользоваться ли этой возможностью.
Когда нули не нужны вообще в программе, то определенно имеет смысл сделать такую функцию.
Еще мне кажется можно попробовать выжать из этого что то:
Код: Выделить всё
m[2] = b/100; //СОТНИ 255/100=2 5/100 = 0
m[1] = ( b - (m[2]*100) ) / 10; //ДЕСЯТКИ (255-(2*100)) / 10 =5 5-(0*100) /10 = 0
m[0] = ( b - (m[2]*100) - (m[1]*10) ) % 10; //ЕДИНИЦЫ( 255 - (2*100) - (5*10) ) % 10;
Смотрите, есть переменная, которую нужно преобразовать, ее можно тоже в цикле делить на десять и инициализировать массив. При этом код для всех декад становится одинаков и позволит оформить данное преобразование в виде цикла.
Не знаю будет ли выгодно для 3х декад но от 10ти и выше точно выгода будет. Нужно пробовать.
Re: помогите оптимизировать код по размеру
Добавлено: Вт сен 02, 2014 15:09:39
ESWANT
ARV писал(а):Код: Выделить всё
#include <string.h>
#include <stdlib.h>
// предельное количество знаков в строке
#define MAXLEN 3
void byte_to_str(char s[], unsigned char fill, unsigned char byte){
unsigned char i, len;
itoa(byte,s,10); // получили 10-е число в виде строки
if(!fill) return; // если не надо добавлять нули слева - конец работы
len = strlen(s); // вычислили длину строки
memmove(s+MAXLEN-len, s, len); // передвинули символы в конец строки
s[MAXLEN] = 0; // поставили терминатор в конец строки
// в цикле дополняем нулями слева полученное число
while(MAXLEN-len){
s[MAXLEN-len-1] = '0';
len++;
}
}
как-то так...
а если byte = 255
а передали s размером всего для двух байт + для \0
и fill =2
переполнение же будет?
содержимое s при выходе из функции должно сохраниться
вы быстрей написали вариант
что скажете о моем?
Re: помогите оптимизировать код по размеру
Добавлено: Вт сен 02, 2014 15:19:11
ESWANT
Gisteresis писал(а):Еще мне кажется можно попробовать выжать из этого что то:
Код: Выделить всё
m[2] = b/100; //СОТНИ 255/100=2 5/100 = 0
m[1] = ( b - (m[2]*100) ) / 10; //ДЕСЯТКИ (255-(2*100)) / 10 =5 5-(0*100) /10 = 0
m[0] = ( b - (m[2]*100) - (m[1]*10) ) % 10; //ЕДИНИЦЫ( 255 - (2*100) - (5*10) ) % 10;
Смотрите, есть переменная, которую нужно преобразовать, ее можно тоже в цикле делить на десять и инициализировать массив. При этом код для всех декад становится одинаков и позволит оформить данное преобразование в виде цикла.
Не знаю будет ли выгодно для 3х декад но от 10ти и выше точно выгода будет. Нужно пробовать.
Компилировать попробую только дома
Про вычисление разрядов тоже подумаю, хотя для байта может и не выгодно
так то мне еще надо и int преобразовывать в строку но там только без ведущих нулей
я там использую sprintf
может там еще сэкономить и полностью уйти от библиотечных
так как мне весь функционал sprintf и не нужен,
только там опять отрицательные числа хорошо делаются
Re: помогите оптимизировать код по размеру
Добавлено: Вт сен 02, 2014 15:23:02
ARV
ESWANT писал(а):
а если byte = 255
а передали s размером всего для двух байт + для \0
и fill =2
переполнение же будет?
содержимое s при выходе из функции должно сохраниться
вы быстрей написали вариант
что скажете о моем?
1. MAXLEN определяет как длину результата, так и размер буфера под него. то есть вы обязаны определить в свой программе массив str[MAXLEN+1] для передачи его в функцию.
2. массив s принимает результат работы функции, как его по-вашему надо сохранять при выходе?!
3. ваш вариант не хочу анализировать, для меня слишком сложно.
4. если для sprintf использовать нужный формат, он может и "левые нули" добавлять. изучайте форматы

Re: помогите оптимизировать код по размеру
Добавлено: Вт сен 02, 2014 15:24:51
Gisteresis
Код: Выделить всё
itoa(byte,s,10); // получили 10-е число в виде строки
А itoa сколько сожрет? Я так понял место критично, поэтому пляски с собственной функцией.
Для предложенного варианта AVR можно в теле функции задаваться не макросом а длиной переданной строки. Тогда не будет краха проги. Это для варианта, если длина заранее неизвестна.
ПС: Если вы вообще мазохист, то вам следует пройтись по форумам ассемблерщиков, там такие чудеса творят... я такой математики до них не видывал... и код запихают в любое место, любого размера...
Re: помогите оптимизировать код по размеру
Добавлено: Вт сен 02, 2014 15:28:02
ARV
Gisteresis писал(а):Код: Выделить всё
itoa(byte,s,10); // получили 10-е число в виде строки
А itoa сколько сожрет? Я так понял место критично, поэтому пляски с собственной функцией.
Для предложенного варианта AVR можно в теле функции задаваться не макросом а длиной переданной строки. Тогда не будет краха проги. Это для варианта, если длина заранее неизвестна.
моя функция вместе с простейшим main для теста сожрала около 380 байт (WinAVR).
в теле функции невозможно узнать, буфер какого размера передан в функцию для приема результата - это проблема программиста. использование в программе для задания размера буфера макроса MAXLEN+1 гарантирует, что переполнений не будет.
Re: помогите оптимизировать код по размеру
Добавлено: Вт сен 02, 2014 15:33:31
Gisteresis
ARV писал(а):в теле функции невозможно узнать, буфер какого размера передан в функцию для приема результата - это проблема программиста.
Тупанул, подумал, что у нас есть модуль динамического выделения памяти как в ОС

Вы правы.
Re: помогите оптимизировать код по размеру
Добавлено: Ср сен 03, 2014 05:49:02
ESWANT
Попробовал мой(рожденный на форуме) вариант - стало на 20 слов меньше
15185-16165
асемблер никак не подходит
по поводу переполнения Вы меня запутали рассуждениями
я имею ввиду что:
передается байт(unsigned char) - там число может быть от 0 до 255
и передается указатель на (ну фактически на набор байтов) строку
она может быть обьявлена unsigned char str[4] или unsigned char[3]
(в последнем элементе место под '\0')
опять же для экономии лишний байт не выделяю
тоесть при вызове функции не известно сколько места есть
И передавая f я гарантирую что только f-символов будет в строке
причем исходный байт поступает из 'вне' неизвестно с каким значением
например byte=255, а по логике программы мне нужно сгенерировать только 2 символа
в моем алгоритме результат будет '55' и никакого превышения
Спасибо, так-то помогло уменьшить размер
правда ещё логику работы не проверял, но надеюсь всё нормально преобразовывается
Попробую потом расширить на int (вдруг получится меньше чем sprintf)
Re: помогите оптимизировать код по размеру
Добавлено: Ср сен 03, 2014 06:49:50
ARV
создается впечатление, что опыт программирования МК у вас неболшой, а вот код - что-то подозрительно велик... вы оптимизацию включили вообще?
Re: помогите оптимизировать код по размеру
Добавлено: Ср сен 03, 2014 10:40:12
ESWANT
ARV писал(а):создается впечатление, что опыт программирования МК у вас неболшой, а вот код - что-то подозрительно велик... вы оптимизацию включили вообще?
Впечатление всегда обманчиво, все же люди разные,
Опыт вещь относительная, что то использовал, что то не довелось...
Я далеко не гуру, конечно...
Код действительно большой Mega32 под завязку....
Причем он достаточно оптимальный...
Проект успешно работает у меня с 2007 года,
успел поменять аппаратную платформу с 1878ВЕ1 на PIC16... на Mega16 и наконец на Mega32
И всё это никогда не мешает мне задавать дурацкие вопросы

Re: помогите оптимизировать код по размеру
Добавлено: Ср сен 03, 2014 10:42:15
ibiza11
ESWANT писал(а):Причем он достаточно оптимальный...
Это Вы как определили?
Код: Выделить всё
__flash uint8_t deg[] = {
100,
10,
1 };
void bin2ascii(char * str, uint8_t value, uint8_t zeroes){
uint8_t i, digit_value;
for(i = 0; i <= 2; i++){
digit_value = 0;
while(value >= deg[i]){
value -= deg[i];
digit_value++;
}
*str = digit_value + '0';
if(!(digit_value)){
if(zeroes){
str++;
}
} else {
str++;
}
}
str++;
*str = 0;
}
как Вам такой вариант?
Re: помогите оптимизировать код по размеру
Добавлено: Ср сен 03, 2014 11:10:36
ARV
к чему все эти извраты в виде попытки оказаться от умножения/деления? крайне маловероятно, что в программе не используются операции деления/умножения, а значит, подпрограммы этих операций в коде уже присутствуют - почему бы не использовать их? если человек ползуется sprintf-ами, то и к быстродействию особых требований не предъявляется... да и операция деления в конечном итоге тоже вычитаниями/сложениями реализована наверняка...
Re: помогите оптимизировать код по размеру
Добавлено: Ср сен 03, 2014 13:42:36
ESWANT
ibiza11 писал(а): как Вам такой вариант?
Спасибо
Попробую обязательно, сравню, напишу результат
Щас только въеду в логику Вашу
Re: помогите оптимизировать код по размеру
Добавлено: Ср сен 03, 2014 13:46:18
ESWANT
ARV писал(а):к чему все эти извраты в виде попытки оказаться от умножения/деления? ...
Да действительно умножение деление есть да еще и с long int
А чё sprintf интересно насколько тяжеловесная,
может от нее вообще отказаться ...