Ritkán kell C-ben dolgoznom, leginkább mikrokontrollerek esetén, és akkor is zömében Arduino környezetben, ahol elég kényelmes String osztály érhető el.
Most azonban ESPIDF alapon kellene SVG-t generálnom, sok mérési adat megjelenítéséhez. Ehhez sok stringet kellene összefűznöm, és sprintf műveletekkel kitöltenem. Kerestem valami kényelmesebben kezelhető String osztályt, amit használhatnék, de nem találtam. Nekiállhatnék megírni, de olyan nehezen hiszem el, hogy ezt ne csinálták volna már meg ezren.
Tudtok valami kényelmesen használható C String osztályt, amit egyszerűen használhatnék? Fontos az append és az sprintf szerű formátumkezelés.
- 564 megtekintés
Hozzászólások
Mintha lattam volna C++-t ESPIDF-hez. Nem foglalkoztam vele igazan, mert be vagyok oltva ellene :)
Hogy string osztaly keresel C-hez, azt nem ertem...
- A hozzászóláshoz be kell jelentkezni
Ez alapján simán integrálva vannak az Arduino libek, ha azt ismered, miért nem használod azt: https://medium.com/home-wireless/how-to-program-an-esp32-in-arduino-whi…
- A hozzászóláshoz be kell jelentkezni
Azért, mert az ESP32 alapból elég lassú IO kezeléssel rendelkezik, nekem meg 100ns-os mintavételezésre van szükségem. Ezt egyelőre csak ESPIDF környezetben tudtam megcsinálni, de ott nem tudom az Arduino-s kódokat használni.
- A hozzászóláshoz be kell jelentkezni
De a link alapján tudsz ESP IDF API-t használni Arduino API-val egy projektben.
- A hozzászóláshoz be kell jelentkezni
Elmentettem, koszi!
Nem biztos, hogy egy projekten (egy "futtathato") belul kevernem. Viszont esetleg tobb taskra lehetne bontani a feladatot. Vannak idokorlatos reszek, es van, ami raer.
- A hozzászóláshoz be kell jelentkezni
Ez lehetséges, de nálam pont fordított a helyzet. ESP IDF projektben kellene Arduino API-t használnom, és ez nem ment.
Arra, hogy egy magot kikapcsoljak a rendszer felügyelete alól, és csak mintavételezésre használjam, ESP IDF projektet találtam mintául.
Lehet, hogy működne a módszer Arduino projekt alapon is, de az átállást erre és tesztelést egyelőre nagyobb szopásnak érzem, mint ESP IDF alatt stringet kezelni.
Később lehet, hogy tesztelni fogom azért ezt a módszert is, mert Arduino környezetben sokkal több könyvtár elérhető.
- A hozzászóláshoz be kell jelentkezni
Ehhez sok stringet kellene összefűznöm, és sprintf műveletekkel kitöltenem.
String összefűzésre esetleg strcat egy for ciklusba téve?
- A hozzászóláshoz be kell jelentkezni
A sok allokálással és a memória töredezésével van gondom, arról nem is szólva, hogy ha én írok meg valamit, abban biztos lesz még három olyan bug, amit más már leszopott. Tehát nekem valami ilyesmi felület kellene:
#include "LamaString.h"
...
LamaString line = LamaString.sprintf("<line x1='%d' y1='%d' x1='%d' y1='%d'/>",x1,y1,x2,y2);
LamaString svg = "<svg>".append( line ) . append( "</svg>" );
Persze, ha C-ben senki nem használja így a Stringeket, akkor implementálom magam, csak azt gondoltam, ez azért elég alap probléma ahhoz, hogy már sok megoldás született rá.
- A hozzászóláshoz be kell jelentkezni
Beágyazott (időkritikus) rendszerben felejtsd el az allokálást/felszabadítást. Használj statikus buffert. Ha nincs elég RAM, akkor allokálással sem fog menni.
Gábor
- A hozzászóláshoz be kell jelentkezni
C-ben ha sok allokálás van akkor te rontasz el valamit. A stacken kell dolgozni.
- A hozzászóláshoz be kell jelentkezni
strcat(string1, string2); // Mindkettőnek "\0"-ra kell végződnie.
> Sol omnibus lucet.
- A hozzászóláshoz be kell jelentkezni
Van ilyen sprintf-re is? Mármint ami maga allokál is hozzá?
- A hozzászóláshoz be kell jelentkezni
Nem értem az "ilyen" szót ebben a kontextusban, hiszen a strcat nem "ilyen".
Viszont szerintem az asprintf()-et keresed.
- A hozzászóláshoz be kell jelentkezni
Igen, az zavart meg, hogy az strcpy értéke is char*. De ezek szerint nem allokál.
Azonban azt hiszem az asprintf valóban jó nekem, köszönöm!
- A hozzászóláshoz be kell jelentkezni
snprintf-re az általános megoldás, hogy először NULL-t adsz át a célpointer helyett, akkor az snprintf kiszámolja neked, hogy mennyi hely kell. Allokálod azt a helyet, és utána a második snprintf hívásnak már az újonnan allokált helyet adod át. Kérdés, hogy ez neked belefér-e az időkorlátba.
- A hozzászóláshoz be kell jelentkezni
asprintf/vasprintf, GNU-extension.
- A hozzászóláshoz be kell jelentkezni
Idővel lassú lesz, mivel strlen(string1)
-gyel kezdődik. Jobb követni, hogy hol jár a string vége:
char *p= buff;
char *plim= buff + sizeof buff;
p += sprintf(p, "Hőfok=%d", 37);
p += sprintf(p, ",páratartalom=%s", foo);
p += strlcpy(p, ",kiegeszites", plim-p);
Meg ugye az sprintf helyett jobb lenne egy snprintf, esetleg így:
unsigned mysnprintf(char *to, size_t size, const char *fmt, ...) {
va_list ap;
int len;
unsigned retlen= 0;
if (size==0) goto RETURN;
va_start(ap, fmt);
len= vsnprintf(to, size, fmt, ap);
va_end(ap);
if (len<=0) {
retlen= 0;
} else if ((unsigned)len >= size) {
retlen= size-1;
} else {
retlen= len;
}
/* to[retlen]= '\0'; ha nem bizunk 100%-ig a vsnprintf-ben */
RETURN:
return retlen;
}
char *p= buff;
char *plim= buff + sizeof buff;
p += mysnprintf(p, plim-p, "Hőfok=%d", 37);
- A hozzászóláshoz be kell jelentkezni
+1: a standard stringműveleteket nem szerencsés hosszú string összefűzésére használni, de ha muszáj, akkor így kell.
- A hozzászóláshoz be kell jelentkezni
Nem jobb lenne, hanem az kell. El kéne felejteni a buffer overflow generátor kifejezéseket.
- A hozzászóláshoz be kell jelentkezni
Szerintem maradj a kályhánál. A string.h lib nagyon sztenderd, minden platformon van, nem az Arduino sajátossága, felesleges feltalálni a kereket. Ez C, ami 50+ éve fel van találva, nem Rust meg stb., ahol modern mindenfélével lehet lustulni. Igen, nem szép a printf, sprintf szintaxisa, ma már archaikusnak és hieroglifának hat, de kis gyakorlással hozzászoksz. Most még kényelmetlen, mert nem szoktál hozzá.
Esetleg ha csak SVG készítése a cél, akkor ahhoz lehet jobban járnál valami interpretált scriptnyelvvel, Python, Lua, Perl, ahol elérhető külön SVG-s modul, ha nem zavar, hogy kicsit lassabban fog futni, mint egy lefordított bináris.
“Windows 95/98: 32 bit extension and a graphical shell for a 16 bit patch to an 8 bit operating system originally coded for a 4 bit microprocessor, written by a 2 bit company that can't stand 1 bit of competition.”
- A hozzászóláshoz be kell jelentkezni
Amikor routerek fw-ét programoztam, a legnagyobb félelmünk egy esetleges underrun/overflow probléma, az invalid pointer dereferencing, illetve a memory leak volt.
Kezdetben a BSD-s fiúk féle ún. n-es függvényekkel dolgoztam. Ebben az volt a szar, hogy könyvelnem kellett a hosszokat is (vagy minden sztringműveletnél leszámoltatni), illetve nem volt automatikus újraallokáció.
Aztán mivel később más miatt is kellett glib, áttértem annak a GString típusára és függvényeire. Ez megoldja az allokációt egy köztes réteggel (valójában slice-okat allokál, és szükség esetén ezekből könyvel Neked területet, tehát nem futsz bele durva allokációs overhead-be valami szerencsétlen esetben, mert a lib ezt okosan kezeli).
De ezek x86 procis eszközök voltak, már akkor GB-os nagyságrendű memóriával. Egy ESP32-n valószínű nem ez lesz az optimális megoldás.
A másik véglet, amikor számológépre fejlesztettem C-ben (TI-89-re), ott mindent magadnak meg kellett csinálni. Amit csak lehetett, igyekeztem pointer-aritmetikával megúszni.
Nem tudom mennyire összetettek a sztringműveleteid. Ha kb. azonos substring-eket kell csak variálnod, esetleg közéjük fosni néhány értéket, akkor ezekből minél többet érdemes statikusan tárolni a memóriában (akár az egyes számjegyeket is!), és a manipuláló függvények egy ,,pointer-string"-en vagy tömbön dolgoznának.
Saját printf() implementációd pl. egy ilyen pointer-string-et kap, aminek minden szava egy pointer: kiírja az adott címen lévő string-et, \0 elérésekor ugrik a következő pointerre, és így tovább.
Amikor értékeket kell behelyettesíteni, van, hogy a leggyakoribb értékeket vagy akár az egyes számjegyeket is letárolom egy sztringben, és a pointerükkel hivatkozok rájuk. Olcsóbbra jöhet ki, mint egy ,,okos" printf() függvényt hívni, formátumsztring-feldolgozással. (HP kalkulátoroknál egyébként RPL nyelven is szokás ez: a számok talán 20-ig elérhetőek memóriacímen is, ami jóval olcsóbb, mintha értékként kellene feldobni őket a stack-re.)
Embedded hardverre - hacsak nem találsz valami nagyon jó kész lib-et - érdemes a hw sajátosságait figyelembe véve megírni néhány nagyon egyszerű elemi függvényt, és ezekre építeni. Szerintem.
- A hozzászóláshoz be kell jelentkezni
Most azonban ESPIDF alapon kellene SVG-t generálnom, sok mérési adat megjelenítéséhez.
Mekkora lesz az az SVG, ami itt készül? Annak fényében, hogy a ketyerédben van kb. 300KB RAM, én úgy gondolom, hogy mondjuk olyan 20-30KB-ig vagy jó, ha ennél nagyobb lenne a fájl, akkor jön az a verzió, hogy raksz mellé egy full featured OS-t futtató gépet (mondjuk valami linuxos *Pi, sok-sok száz MB RAM-mal), oda átküldöd az adatot minimális formázással, és majd ott csinálsz belőle weboldalt.
És 20-30KB-ig pedig statikus, fix méretű pufferbe gyűjteném a fájl tartalmát.
- A hozzászóláshoz be kell jelentkezni
+1 Mikrokontrolleren a sting libekkel az lesz a probléma, hogy folyton dinamikusan akarnak allokálni memóriát.
Ilyen környezetben ha csak lehet fix pufferbe kell dolgozni. Ha nem fér be a memóriába az eredmény, akkor pedig streamelni kell, ahogy előáll az eredmény egy része már küldeni is kell a célnak és újrahasznosítani a buffert.
Van egy jópofa template megoldás, ami fejlesztési időben csinál template<->forráskód konverziót: https://github.com/qgears/rtemplate#rtemplate
Ezzel csináltam már olyat, hogy mikrovezérlő állított elő hosszú generált szöveget, amit egy nyomtatóra streamelt. Ez a leghatékonyabb módja a szöveg generálásnak mind template szerkesztés, mind runtime teljesítmény szempontjából azok közül amit ismerek.
- A hozzászóláshoz be kell jelentkezni
Igen, lehet, hogy nálam is ehhez kell majd folyamodni. Jelenleg 600 mintavételezést tudok begyűjteni (60us), ha az ESP generálja hozzá az SVG kiértékelést. De ha javascripttel tudnék SVG-t generálni - márpedig, ha jól látom, lehet -, akkor az ESP-nek csak be kellene gyűjteni az adatokat, és átküldeni a böngészőnek, amiben a javascript majd kiértékeli. Mivel egy mintavételezés eredménye 4 bájton tárolható, várhatóan 60000 mintát is be tudnék (6ms) gyűjteni az elemzéshez. Már, ha valami egyszerű formában, át tudok küldeni 60000 4 bájtos bináris adatot a javascript részére. Ennek még nem jártam utána.
- A hozzászóláshoz be kell jelentkezni