Kysymys:
muistin käyttö "ohjeet ja kiellot"
Randy
2018-02-24 00:16:05 UTC
view on stackexchange narkive permalink

Vaikka olen kirjoittanut C / C ++ -koodia pitkään, näkymättömät rajoitukset sille, kuinka muistia kulutettiin erilaisille MCU- ja SOC-ohjelmointialustoille, ovat usein minua kaataneet. Kun aion rakentaa koodia ensimmäiselle suurelle projektilleni NANO-levyjäni varten, joka todennäköisesti käyttää kohtuullisen määrän resurssejaan, haluaisin olla paremmin valmistautunut yllättäviin ja odottamattomiin "gotchoihin", joihin kannattaa varoa. .

Esimerkiksi toisella SOC: lla, jonka parissa työskentelin äskettäin laajasti (The Pololu.com wixel), olin hyvin yllättynyt kuullessani funktion / menetelmän argumentit ja automaattiset muuttujat, joiden odotan tavallisesti jakavan pinon ja palautui, kun funktion palautukset oli tosiasiallisesti varattu ohjelman koko elinkaarelle! Vau! Joten tällä alustalla, jossa yleensä vihaisin muuttujien ylikuormittamista tai muuttujien uudelleenkäyttöä sen jälkeen, kun niiden nimillä ei enää ole merkitystä, jouduin mukauttamaan koodaukseni siihen, mitä luulisin yleensä olevan huono. Puhumattakaan siitä, että ymmärretään, että yksinkertaiset silmukka-muuttujat allokoitiin paremmin globaalisti. Yecch!

Voivatko ne teistä, joille on sattunut odottamattomia koodausongelmia Arduino-ympäristössä, jakaa "erityisiä" ohjeita tällaisista asioista?

"auto" muutettu tallennuksen kestomäärittimestä muuttujatyyppimääritteeksi C ++ 11: ssä. Älä käytä yksinkertaisuuden vuoksi `` auto``.
positiivinen yllätys minulle on taulukon allokointi pinolle, jonka koko on muuttujasta https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html
Voi ... gee ... anteeksi ... En koskaan tarkoittanut päätellä, että olen koskaan käyttänyt 'auto' -avainsanaa (unohdin sen edes olemassa olevan!). Tarkoitin vain mitä oletusarvo oli toiminnon sisällä ilmoitetuille ei-staattisille muuttujille.
Kaksi vastused:
Edgar Bonet
2018-02-24 01:14:00 UTC
view on stackexchange narkive permalink

Kuten olet huomannut itsesi, tämä voi olla jonkin verran alustasta riippuvainen. Koska työskentelet nanon parissa, vastaukseni tulee olemaan AVRarchitecture, kun se on käännetty gcc: llä, avr-libc: llä ja Arduino corelibraryilla.

Ensinnäkin haluan rauhoittaa teitä: tätä outoa käyttäytymistä, jonka näitte Wixeldoista, ei tapahdu tällä alustalla. Paikalliset muuttujat varataan enimmäkseen CPU-rekistereihin, sitten pinoon.

Nyt ensimmäinen yleissääntö saattaa kuulostaa itsestään selvältä: mieti kahdesti, mitä sinun ohjelmasi todella on muistettava. Käytä myös joka kerta pienintä mahdollista tietotyyppiä. C99-tyypit int8_t , uint16_t ja vastaavat ovat hyödyllisiä tässä.

Toinen sääntö, jonka kuulet usein tällä alustalla: vältä dynaamista kohdistamista, ts. code> malloc () ja new , koska usein ei ole varaa kasaan pirstoutumista. Vältä myös String -luokkaa, koska se perustuu dynaamiseen allokointiin. Valitse mieluummin staattinen allokointi tai pinoaminen pienille asioille.

Älä unohda käyttää vakioille const : tämän määritteen avulla kääntäjä voi usein optimoida vakiot välittömiksi operandeiksi. Käytä vakioiden ennakointia käyttämällä PROGMEM . Kyllä, se ei ole mukava käyttää, mutta se voi säästää paljon RAM-muistia. F () -makro vakioviestien tulostamiseen on erityistapaus PROGMEM.

Viimeiseksi, ole varovainen rekursioiden suhteen.

Kiitos. Hyviä puolia! Vältä yleensä mallocia tai 'uutta' sulautetussa ohjelmassa, varsinkin sellaisessa, joka saattaa toimia ilman valvontaa pitkään aikaan. Ja minäkin olen käyttänyt kooditila-muistia mihinkään rakenteeseen tai matriisiin, jotka eivät koskaan muutu. Tai jopa EEprom rakentaa asioita, kuten asetuksia. Mutta vain se, että toimintomuuttujat ovat pinopohjaisia, on ERITTÄIN hyvä uutinen. Aloin huolestua nähdessäni niin paljon esimerkkikoodia, jossa samaa var-nimeä käytettiin uudestaan ​​ja uudestaan, vaikka sen nimellä ei enää olisikaan ollut merkitystä.
Myös tämä viimeinen kohta on mielenkiintoinen! Ihmettelen, tekisikö rekursiivinen toiminto, joka räjäytti pinonsa rajan, köyhän laudan melkein saavuttamattomaksi, koska se juoksisi aina samaan aukkoon aina, kun se näki virtaa. Se ei ole kuin vanhat laitteet, jotka voisit pakottaa pysähtymään CTRL-C-virralla, joka lähetetään käynnistyksen aikana!
@Randy: Pinoa ei ole rajoitettu. Jos ylikuormitat pinosi, alat vain kirjoittaa ohjelman kasan, jos sellainen on, sitten .bss-osio ja sitten .data-osa.
Ei ole oikein sanoa, että asioita tapahtuu tai ei tapahdu tietyllä * sirulla *, kun ne ovat * työkaluketjun * tai jopa * kielimäärityksen * todellisuudessa * laitteiston * sijaan.
@ChrisStratton: Olet oikeassa. Lisäsin vastaukseen vastauksen. Toisaalta AVR suunniteltiin kokoamista ajatellen. Olisi typerää (vaikkakin varmasti mahdollista) kääntäjän olla käyttämättä rekisteritiedostoa ja pinoosoitinta sellaisina kuin ne on suunniteltu käytettäväksi.
Eric Dand
2018-02-24 08:23:19 UTC
view on stackexchange narkive permalink

Edgarilla on hyviä vinkkejä, ja toistan yhden ennen muutaman lisää antamista:

vältä dynaamista muistin allokointia

Älä käytä malloc. Kun suunnittelet järjestelmää, budjetoi RAM-muistisi samalla tavalla kuin kuukausibudjettisi. Varmista, että pystyt tekemään kaiken kerralla.

Ja muutama muu vinkki:

globaali statistiikka

Hyödynnä BSS-lohko täysimääräisesti; yritä estää tilaa niin paljon kuin mahdollista globaaleissa static -ryhmissä. Voit järkyttää tai pilkata ajatusta sijoittaa kaikki globaalille tasolle, mutta upotettu on paradigman muutos, jolla on omat säännöt.

Koska sinulla on niin paljon muuttujia globaalilla tasolla, staattinen auttaa välttämään nimitilaasi saastuttamasta liikaa.

Vältä hienoja C ++ -ominaisuuksia

Yritä itse asiassa olla käyttämättä C ++ ollenkaan. C ++ vie sinut "kauemmas metallista" RAII: lla, rakentajillaan ja implisiittisellä tyyppimuunnoksellaan ... On paljon vaikeampaa pitää tiukka luettelo kaikista resursseistasi, kun kielesi tekee niin paljon kulissien takana. Jos haluat todella käyttää tiettyä C ++ -kielitoimintoa, yritä pitää koodisi sävy enemmän kuin "C, jossa on bittiä C ++", eikä "C ++, joka on upotettu upotettuun järjestelmään". Se ei mene koskaan hyvin.

Vältä erityisesti geneerisiä aineistoja / malleja, jotka kuluttavat paljon muistiasi. Joka kerta, kun käytät uutta tyyppiä mallin kanssa koodissasi, ohjelmaan kootaan toinen kopio malliluokasta, vain kyseiselle tyypille. Oletko koskaan miettinyt, miksi C ++ -binaaritiedostot voivat ilmapalloa 20, 50, jopa 100 Mt: iin? Mallit, mies. Mallit.

const

Tämän avainsanan tulisi sisältää niin monta muuttujaa kuin mahdollista. Tämän tavan säilyttäminen säästää sekä suoritus- että tilankulutusta. Opi ero const T * foo , T * const foo ja const T * const foo välillä.

Liian paljon tästä on hölynpölyä sivuuttamatta. Jotkut tästä ovat hyviä, mutta joukon globaalien valtioiden suositteleminen on vain huonoja neuvoja, ja monet ihmiset käyttävät C ++: ta tällaiseen ohjelmointiin. Upotettu ei ole tekosyy kirjoittaa vaikeasti ylläpidettävä koodi.
Lisäksi C ++ -mallien ei tarvitse olla niin painavia kuin teet niistä. Tärkeintä on varmistaa, että käännät linkki-ajan optimoinnilla, jotta jokaisella yksittäisellä objektitiedostolla ei ole * omaa * kopiota kustakin käyttämästään mallierittelystä. Kymmenen erilaista kopiota `vektorista `, yksi kussakin kymmenestä lähdetiedostosta, on hieman hankala, mutta LTO: n avulla kääntäjä / linkittäjä voi deduplikoida ne yhdeksi jaetuksi kopioksi. Jos tarvitset toiminnallisuutta, mallipohjainen koodi (varsinkin LTO-rivinvaihdon jälkeen) on usein kooltaan melko samanlainen kuin mitä kirjoitat käsin.
Älä tee muuttujasta globaalia, jos sitä käytetään vain yhdessä toiminnossa. Tee se "staattiseksi", jos arvo on muistettava kutsusta kutsuun. Alakohtaisesti staattinen paikallinen on sama kuin globaali.
Kiitos vinkeistä. Näen joidenkin ansioiden pienten järjestelmien kannalta. Vaikka olen nähnyt C ++ -kääntäjien tulevan pitkälle, olen silti haluttava käyttämään "puhdasta" C ++: ta ja olemaan 100% OOP koodin joka nurkassa. Joskus sen ylivoima. Mutta vakiintuneiden toimintojen rakentaminen luokkiin, jotka voit piilottaa kirjastossa, tekee sovelluksestasi helpommin seurattavan.


Tämä Q & A käännettiin automaattisesti englanniksi.Alkuperäinen sisältö on saatavilla stackexchange-palvelussa, jota kiitämme cc by-sa 3.0-lisenssistä, jolla sitä jaetaan.
Loading...