Точно разкарах printf & friends, че трябва да навра кво ли не 32кб - нормалния принтф иде с поддръжка за числа с плаваща запетая и лесно добавя едно 10-на кб. С целия ХАЛ за СТ32 + Зефир нишки, драйвери и т.н. и стана 31кб Т.е. трябва да имаш ама наистина много принтф, че да стане по оптимално да е отделна функция а не сдъвкан по време на компилация до отделни примитиви за печат. На практика почти никой не си играе да оптимизира чак до толкоа - или ползваш дебелия принтф със всички благинки или го махаш изцяло като мен. Въпреки, че Зефиря има и някакъв скопен вариант в който добавя само 2-3кб но мисля, че успях да го излъжа да подкарам логовете и пак да ми останат 10-на кб за моя код.
Е той Ребата каза, че използва някаква нестандартна имплементация. Ако не трябва да парсва неща като %04 и т.н. сигурно не е много сложна. Моята идея прави нещата малко по-оптимални в смисъл че се свързват само частите, които реално се използват. Ако нямаш %d, няма да се свърже печатането на десетични числа.
Иначе стандартната printf е ужасно голяма, поне в glibc. Тя вика и разните функции от i18n да знае в зависимост от стойността на LANG какво да използва за десетична запетая/точка и т.н. Не си спомням защо ми трябваше статично линкнато байнъри, но се хванах за главата като видях какво се случи като сложих един printf. :)
Реба Създадено на 21.12.2024, видяно: 176 пъти. #129845
ти и да го сдъвчеш при компилация, пак го разбиваш на функции които вътрешно принтф вика, не си мисли че ще изчезнат. самото принтф е мизерно, сигурно няма и 200 байта, ето го моето
void __attribute__((noinline)) printf(const char* format,...){
if(!format||!serial)return;
__builtin_va_list argList;
const char *p;
char buf[12];// za printene na chisla
__builtin_va_start(argList, format);
for(p=format;*p;p++){
char c=*p;
char c1=p[1];
if(c=='%'){
unsigned int v=__builtin_va_arg(argList,unsigned int);
char *dig=buf;// tuka malko habim edin simwol (buf[0]), ako startirame s buf-1 bi mogyl da se spesti
if(c1=='d'||c1=='u'){
}else
if(c1=='%f'||c1=='%g'){
}else
if(c1=='x'||c1=='X'){
c1-='x'-'a'+10;//konwertira go kym 'A' ili 'a' s ofset 10 za da prewyrne 0xA->'A'
do{
dig++;
*dig=v&0xf;
*dig+=(*dig>9)?c1:'0';
v>>=4;
}while(v);
}else
if(c1=='s'){
char *s=(char*)v;
for(;*s;s++)putchar(*s);
}else
if(!c1)break;
p++;
while(dig>buf){
putchar(*dig);
dig--;
}
}else if(c=='\\'){
if(c1=='\\')putchar('\\');else
if(c1=='n')putchar('\n');else
if(c1=='r')putchar('\r');else
if(c1=='t')putchar('\t');else
if(!c1)break;
p++;
}else{
putchar(c);
}
}
__builtin_va_end(argList);
}
Реба Създадено на 21.12.2024, видяно: 176 пъти. #129846
аз дори само за това не бих ползвал стандартен принтф. това е толкова ВРЕДНО само по себе си, мани дето раздува кода но е ВРЕДНО, хората си пишат собствен принт и парсване за флоати само за да не се набодат на тоя хуй с принтф локализацията
Принтф е програмиския аналог на тъждеството - бял ляп === църна локализация, даже да не ти трябва :)
Реба Създадено на 22.12.2024, видяно: 132 пъти. #129930
днес реших че много се бавя докато дебъгвам и по-добре да си допиша принтф да вади и десетично, ето как го направих, няма нито делене, нито умножение дори.
static u32 pow10[]={1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000};
....
if(c1=='d'&&(int)v<0){//
putchar('-');// pechatame znaka
v=-(int)v;// premahwame znaka, algorityma e za unsigned
}
int i;
u32 rem=v;// towa koeto ostawa da se dopechata
for(i=9;i>=0;i--){// skaniraneto e ot golemi kym malki, po reda na pechatane
u32 p=pow10[i];//
int c=0;// kolko pyti p se pobira w rem
while(rem>=p){
rem-=p;
c++;
}
if(c||v>p||!i)putchar(c+'0');
}
Може да е по-добре за контролери които нямат 64 битов шифт. За последната цифра може да не се цикли, чуек. Тя си е готова в rem. И май ти спестява една проверка за !i.
for(i=9;i;i--){// skaniraneto e ot golemi kym malki, po reda na pechatane
u32 p=pow10[i];//
int c=0;// kolko pyti p se pobira w rem
while(rem>=p){
rem-=p;
c++;
}
if(c||v>p)putchar(c+'0');
}
putchar( rem + '0' );
Реба Създадено на 22.12.24 18:16, видяно: 94 пъти. #129975
това да изкараш последната цифра извън цикъла отпушва много благинки. като се нареди масива на обратно единицата отпада, прескачането на водещите нули минава отпред и става супер компактно
u32 i,rem=v;// towa koeto ostawa da se dopechata
for(i=0;i<9;i++){// skaniraneto e ot golemi kym malki, po reda na pechatane
u32 c,p=pow10[i];//
if(p>v)continue;
for(c=0;rem>=p;c++)rem-=p;
putchar(c+'0');
}
putchar(rem+'0');
И се замислих, дали няма да се ускори подхода на Дон Реба ако имаме таблица на база 5. С двоично търсене и всички шукарии. И стана един мазаляк...
#define FIVESIZE 19
unsigned utos1( char *s, uint32_t val ) {
static const uint32_t five[FIVESIZE] = {
1,
5,
10,
50,
100,
500,
1000,
5000,
10000,
50000,
100000,
500000,
1000000,
5000000,
10000000,
50000000,
100000000,
500000000,
1000000000
};
unsigned i, j, b, e, c;
for( b = 0, e = FIVESIZE, j = 0; e - b > 0; ) {
i = ( b + e ) >> 1;
if( val >= five[i] ) {
j = i;
b = i + 1;
}else {
e = i;
}
}
for( i = j, j = 0; i > 1; ) {
c = i & 1 ? 5: 0;
val -= i & 1 ? five[i]: 0;
i &= -2;
while( val >= five[i] ) val -= five[i], c++;
--i;
i -= val < five[i];
s[j++] = c + '0';
};
s[j++] = val + '0';
s[j] = 0;
return j;
}