M.Adrian Postat Octombrie 31, 2021 Partajează Postat Octombrie 31, 2021 (editat) Salut, tot caut de ceva timp solutii pentru afisarea unei valori de tip float pe un lcd alfanumeric 1602. Am incercat cu functiile ftoa() si sprintf() dar pe display e afisata valoarea urmata de 5 sau 6 zecimale, chiar daca eu declar acea variabila cu 3 sau alt numar de zecimale. char *buffer; int status; float x=50.123; LCD_SetCursor(1,2); buffer=ftoa(x,&status); LCD_Putstring(buffer); Asa e afisata valoarea x, cu inca 3 zecimale dupa ea, folosind functia ftoa(). char buffer[4]; float x=50.123; LCD_SetCursor(1,2); sprintf(buffer,"%f",x); LCD_Putstring(buffer); Asa e afisata valoarea pe lcd cu functia sprintf(), cand marimea de la buffer e 4, eu am crezut ca marimea de aici e numarul de zecimale care va fi afisat, dar nu e asa, in programul meu, pentru orice valoare >=4 va afisat numarul ca in poza de mai sus, iar daca marimea bufferului e 3, atunci numarul e afisat doar cu 2 zecimale, daca marimea bufferului e 2 sau 1 atunci nu mai apare decat punctul dupa 50. Aa si mai e o ciudatenie, daca scriu acelasi cod folosind sprintf(), dar il scriu ca o functie in biblioteca de la lcd si apelez acea functie in main(), parca ignora complet dimensiunea bufferului iar cand apelez functia imi afiseaza valoarea ca in prima poza, adica cu 6 zecimale dupa ea. void LCD_PrintFloat(float valoare) { char buffer[3]; sprintf(buffer,"%f",valoare); LCD_Putstring(buffer); } Cum as putea sa rezolv problema? Inafara de procesarea valorii prin operatii de tip % sau / in stil clasic. Ce vreau e sa pot afisa valori cu zecimale, dar cu un numar predeterminat de zecimale, in sensul ca daca calculez o valoarea si in urma calculului are 5 zecimale dar eu vreau sa afisez doar 3, sa pot face asta. Editat Octombrie 31, 2021 de M.Adrian Link spre comentariu
mars01 Postat Octombrie 31, 2021 Partajează Postat Octombrie 31, 2021 (editat) Salut! Poti incerca asa: char buffer[20]; float x=50.123; sprintf(buffer,"%.3f",x); LCD_SetCursor(1,2); LCD_Putstring(buffer); Nu este cea mai eficienta metoda, dar functie de compilator ar trebui sa iti ofere ce ai nevoie. PS: dimensiunea bufferului este pentru toate caracterele care formeaza un numar float (daca are minus in fata, punctul separator, partea intreaga, zecimalele). Fiecare digit ocupa un byte din buffer, fie ca este din partea intreaga sau din zecimale. Documentatie sprintf: https://www.tutorialspoint.com/c_standard_library/c_function_sprintf.htm Editat Octombrie 31, 2021 de mars01 Link spre comentariu
Liviu M Postat Octombrie 31, 2021 Partajează Postat Octombrie 31, 2021 (editat) Ce vrea mars01 probabil sa zica e ca trebuie sa folosesti formatele pentru (s)printf ca sa formatezi stringul rezultat asa cum iti trebuie. LE: mars01 a adaugat "informatia lipsa", asa ca postul meu poate fi ignorat. Editat Octombrie 31, 2021 de Liviu M Link spre comentariu
M.Adrian Postat Octombrie 31, 2021 Autor Partajează Postat Octombrie 31, 2021 1 oră în urmă, mars01 a spus: Salut! Poti incerca asa: char buffer[20]; float x=50.123; sprintf(buffer,"%.3f",x); LCD_SetCursor(1,2); LCD_Putstring(buffer); Nu este cea mai eficienta metoda, dar functie de compilator ar trebui sa iti ofere ce ai nevoie. PS: dimensiunea bufferului este pentru toate caracterele care formeaza un numar float (daca are minus in fata, punctul separator, partea intreaga, zecimalele). Fiecare digit ocupa un byte din buffer, fie ca este din partea intreaga sau din zecimale. Documentatie sprintf: https://www.tutorialspoint.com/c_standard_library/c_function_sprintf.htm A mers asa, multumesc! Acum ramane intrebarea de unde apareau zecimalele alea in plus. Link spre comentariu
UDAR Postat Octombrie 31, 2021 Partajează Postat Octombrie 31, 2021 Acum 3 ore, M.Adrian a spus: Acum ramane intrebarea de unde apareau zecimalele alea in plus. Se știe că reprezentarea float nu este o reprezentare exactă ci doar aproximativă. Probabil că valoarea introdusă de tine 50.123 a fost convertită de compilator în cea mai apropiată valoare float care ar fi (în zecimal) 50.123046 . La convertirea înapoi în zecimal a valorii float respective algoritmul a returnat toate zecimalele disponibile. Așa văd eu lucrurile (cel puțin la ora asta ...). Link spre comentariu
Vizitator Postat Noiembrie 1, 2021 Partajează Postat Noiembrie 1, 2021 (editat) Acum 22 ore, M.Adrian a spus: char buffer[4]; float x=50.123; LCD_SetCursor(1,2); sprintf(buffer,"%f",x); Atentie pe viitor si la dimensiune buffer[]. x=50.123 nu are cum sa incapa in 4 octeti dupa conversia din float in string cu sprintf(). Ai o frumusete de buffer overflow mai sus. Si compilatorul nu prea semnalizeaza asta. Si uneori nici in executie nu se manifesta mereu. Poti avea probleme foarte greu de depistat in astfel de cazuri. Editat Noiembrie 1, 2021 de Vizitator Link spre comentariu
modoran Postat Noiembrie 1, 2021 Partajează Postat Noiembrie 1, 2021 Compilatorul nici nu are cum sa semnalizeze asa ceva. Link spre comentariu
M.Adrian Postat Noiembrie 1, 2021 Autor Partajează Postat Noiembrie 1, 2021 Acum 6 ore, Liviu.Mihaiu a spus: Atentie pe viitor si la dimensiune buffer[]. x=50.123 nu are cum sa incapa in 4 octeti dupa conversia din float in string cu sprintf(). Ai o frumusete de buffer overflow mai sus. Si compilatorul nu prea semnalizeaza asta. Si uneori nici in executie nu se manifesta mereu. Poti avea probleme foarte greu de depistat in astfel de cazuri. E bine de retinut asta pe viitor. Pot sti cumva orientativ cam cat ar trebui sa fie dimensiunea bufferului ca sa nu fie probleme, sa zicem in cazul in care afisez o valoare maxima de tipul 999.999? Daca raspunsul se afla in documentatia de la @mars01 pentru sprintf() atunci sa imi fie cu iertare dar inca nu am apucat sa o citesc toata pe indelete. Link spre comentariu
Vizitator Postat Noiembrie 2, 2021 Partajează Postat Noiembrie 2, 2021 (editat) Poti utiliza functia snprintf() pentru a afla dimensiunea minima pentru buffer. Si apoi sa aloci dinamic spatiu pentru buffer: float my_pi=333.141592; int size = snprintf(NULL, 0, "%f", my_pi); char* buffer = malloc(size + 1); // +1 pentru terminatorul '\0' Dar nu cred ca este nevoie de complicatia asta. Editat Noiembrie 2, 2021 de Vizitator Link spre comentariu
M.Adrian Postat Noiembrie 2, 2021 Autor Partajează Postat Noiembrie 2, 2021 E o varianta buna dar in general nu cred ca voi avea nevoie de alocare dinamica de memorie, totusi cred ca e o idee buna sa pot afla cu snprintf dimensiunea pentru buffer si sa o setez fix din start. Multumesc pentru sfaturi! Link spre comentariu
mars01 Postat Noiembrie 2, 2021 Partajează Postat Noiembrie 2, 2021 (editat) Acum 5 ore, Liviu.Mihaiu a spus: Poti utiliza functia snprintf() pentru a afla dimensiunea minima pentru buffer. Si apoi sa aloci dinamic spatiu pentru buffer. Alocarea dinamica este periculoasa pentru acele uC-uri care au o cantitate de memorie redusa pentru ca se creeaza iluzia ca exista suficienta memorie si in anumite conditii se poate ajunge la erori de procesare datorate unui consum mai mare de RAM decat exista (numai vorbim de posibila fragmentare a memoriei care conduce la o pierdere si mai mare a memoriei RAM disponibile). Asa ca mai bine se aloca static de la inceput o valoare maxima a buffer-ului, valoare care se poate seta printr-o directiva #define de ex pentru a face aceasta configurabila. // poate contine un numar real maxim 17digiti in partea intreaga + partea fractionara // din cele 3 elemente ramase avem un posibil semn minus, punctul separator // si caracterul 'NULL' care incheie orice string #define BUFF_LENGTH 20 char buffer[BUFF_LENGTH]; ********************************************************************************************************************************************** Citat E bine de retinut asta pe viitor. Pot sti cumva orientativ cam cat ar trebui sa fie dimensiunea bufferului ca sa nu fie probleme, sa zicem in cazul in care afisez o valoare maxima de tipul 999.999? In acest caz se poate calcula simplu: 1 element pt un posibil semn minus + 3 elemente pentru partea intreaga (999) + 1 element pentru punctul zecimal + 3 elemente in partea fractionara (999) + 1 element pt terminatorul 'NULL' = 9. Prin urmare ar fi suficient: #define BUFF_LENGTH 9 char buffer[BUFF_LENGTH]; Editat Noiembrie 2, 2021 de mars01 Link spre comentariu
M.Adrian Postat Noiembrie 2, 2021 Autor Partajează Postat Noiembrie 2, 2021 Am inteles atunci. Multumesc! Am modificat si bufferul din biblioteca, functioneaza bine vad. Link spre comentariu
Liviu M Postat Noiembrie 2, 2021 Partajează Postat Noiembrie 2, 2021 (editat) Acum, că ai primit răspunsul pe care îl doreai, putem despica puțin firul în 4. Din câte știu eu, sprintf (și similarele) consumă multe resurse. Într-un topic mai vechi al lui Mircea am discutat despre o abordare mai puțin generală dar mai economică. Poate că ți se potrivește? Editat Noiembrie 2, 2021 de Liviu M Link spre comentariu
bcristian Postat Noiembrie 2, 2021 Partajează Postat Noiembrie 2, 2021 Ca principiu, sprintf consuma semnificativ mai multa putere de calcul decat ftoa. Evident, este foarte improbabil ca asta sa fie o problema practica daca vorbim de afisare, care nu are rost sa fie facuta la frecvente mari, oricum. Pe de alta parte, daca platforma nu are deja facuta o functie care sa permita conversia in diverse reprezentari si precizii, folosirea printf e preferabila. Mai ales daca intrebarea e pusa de la nivelul initiatorului. Conversia float > string e semnificativ mai complicata decat pare, un exemplu aici. Mai important insa e altceva - evitarea buffer overflow. Este o greseala foarte usor de facut si cu consecinte potential catastrofale, si mai ales greu de identificat. sprintf, strcpy, si de altfel mai toate functiile "clasice" care scriu in stringuri/buffere sunt foarte pacatoase din punctul asta de vedere, si in standardele actuale sunt depasite, si majoritatea compilatoarelor te si avertizeaza sa nu le folosesti. Exista acum (de mai bine de 10 ani de fapt) variante sigure ale lor, in care trebuie sa specifici si lungimea sirului in care scrii. Pt C++ si array-uri statice existe variante care deduc singure informatia. De exemplu, daca vrem sa scriem intr-un buffer fix, avem snprintf, care se asigura ca nu scriem aiurea prin memorie. Link spre comentariu
Liviu M Postat Noiembrie 2, 2021 Partajează Postat Noiembrie 2, 2021 Depășirea buffer-ului, sprintf/snprintf... fuseseră deja lămurite. În rest, părerea mea e că orice soluție "de biblioteca" (adică care rezolvă orice variantă posibilă de intrare) nu poate fi decât mai puțin eficientă decât variante dedicate (compuse din teste, scăderi și adunări), da' o schimb cu plăcere dacă cu argumente convingătoare. Metoda pe care am menționat-o anterior nu-mi aparține, e plagiată de pe forumul uChip. Link spre comentariu
Postări Recomandate
Creează un cont sau autentifică-te pentru a adăuga comentariu
Trebuie să fi un membru pentru a putea lăsa un comentariu.
Creează un cont
Înregistrează-te pentru un nou cont în comunitatea nostră. Este simplu!
Înregistrează un nou contAutentificare
Ai deja un cont? Autentifică-te aici.
Autentifică-te acum