Kysymys:
C-koodauksen suunnittelu - toiminnon osoittimet?
user17592
2013-01-25 12:27:15 UTC
view on stackexchange narkive permalink

Minulla on PIC18F46K22 ja ohjelmoin sen XC8-kääntäjällä. Loppujen lopuksi minulla on järjestelmä, kuten tietokone, jossa on stdin ja stdout . Joten pääpiirissä on toiminto, joka tarkistaa, onko uutta tuloa. Jos syötettä on, funktio kutsutaan vastaavasti. Joten esimerkiksi kun syötän A-koodin stdin -kohtaan, PIC suorittaa toiminnon, kuten function_A , sijasta function_B , jota kutsutaan syötettäessä B.

Kun PIC on tehty toiminnolla, haluan, että uusi tulo lähetetään funktiolle. Joten kun A-näppäimen painaminen avaa RS232-lähettimen, siitä hetkestä lähtien jokainen tulo lähetetään RS232: n kautta. Loppujen lopuksi projekti on erillinen tekstieditori. Joten kun painetaan A-näppäintä, tiedostojärjestelmä avautuu, siitä hetkestä lähtien et enää muokkaa tekstiä, mutta etsit tiedostoluetteloa. Tämä tarkoittaa, että Ylös- ja Alas-näppäinten painaminen tarkoittaa jotain erilaista kuin tekstinmuokkausympäristössä.

Olen miettinyt paljon, kuinka ohjelmoida tämä C. tietää, onko se mahdollista ja jos on, miten. Haluan tehdä seuraavaa:

  • main -funktio kutsuu funktiota kuten function_A
  • function_A muuttaa globaalin muuttujan function_addr funktion in_function_A
  • osoitinnumerosta lähtien main kutsuu funktio kohdassa function_addr , kun uutta syötettä on.

Tarvitsen siis main -funktion, joka tarkistaa, onko function_addr nolla. Jos näin on, tulisi kutsua 'normaali' toiminto, kuten function_A . Jos se ei ole, tulisi kutsua funktio osoitteessa function_addr . Tarvitsen myös function_A -ominaisuuden, joka vaihtaa function_addr -osoittimen osoittimeksi in_function_A .

Huomaa: kun tiedostojärjestelmätoiminto pitäisi sulkea, is_function_A pitäisi vain muuttaa function_addr arvoksi 0.

Joten kysymykseni on, kuinka voin

  • Hanki funktion osoite (ja tallenna se muuttujaan)
  • Kutsu funktio määritettyyn osoitteeseen
Pois aiheesta. Kuuluu stackoverflow.com-sivustoon.
Minulle tilakoneen lähestymistapa on paljon vähemmän riskialtista kuin toimintoviivojen käsitteleminen. Syöttötavu siirretään tilakoneen rakenteeseen (joka voi olla yhtä yksinkertainen kuin kytkentätapa), joka hyppää useille koodibiteille tilamuuttujan tai muuttujien funktiona. Et myöskään ole täysin selvillä siitä, mistä stdin tulee (ei siitä, että sillä on todella paljon merkitystä, mutta olen utelias).
@EJP olen eri mieltä. Pelkästään päällekkäisyyden takia se ei tarkoita, että sen on oltava jossakin sivustossa. Kummassakin paikassa näyttää olevan kysymys matalien sulautettujen järjestelmien suunnitteluun ja ohjelmointiin liittyvistä kysymyksistä.
Tilakoneet voivat perustua funktion epäsuoraan suuntaan: kutsu tilansiirtofunktioon palauttaa uuden tilasiirtofunktion.
@Kortuk No * olen eri mieltä. Se on tietokoneohjelmointikysymys, eikä sillä ole tarkalleen mitään tekemistä EE: n kanssa, paitsi siltä osin kuin haluat edustaa, että EE sisältää tietokoneohjelmoinnin, mikä ei ole pitkään kokemuksestani jakama uskomus. On myös kysymys siitä, mihin asiaankuuluva asiantuntemus on keskittynyt eniten, ja ei ole epäilystäkään siitä, että SO voittaa mailin verran. Joten kysymys täällä sijasta ei periaatteessa ole järkevä tutkimustapa.
Käydään tämä keskustelu [täällä] (http://meta.electronics.stackexchange.com/questions/2622/are-pure-c-questions-on-topic).
Saatat olla hyödyllistä tarkastella esimerkkejä kirjan viitteistä, kuten https://fi.wikibooks.org/wiki/C_Programming/Pointers_and_arrays#Pointers_to_Functions
Kaksi vastused:
Wouter van Ooijen
2013-01-25 12:39:18 UTC
view on stackexchange narkive permalink

Funktio

  int f (int x) {..}  

Hanki funktion osoite (ja tallenna se muuttujaan)

  int (* fp) (int) = f;  

Kutsu funktio määritettyyn osoitteeseen

  int x = (* fp) (12);  
+1, ilmeinen C- ja ASM-maailmassa, mutta ei niin ilmeinen niille, jotka aloittivat OO-kielillä.
Fp-kutsu voidaan kirjoittaa myös nimellä 'int x = fp (12);' lisätä luettavuutta.
Minun on myönnettävä, että työskentelen pääasiassa C #: ssä ja Javassa tällä hetkellä, kaipaan niitä C: n vanhoja hyviä toimintoviitteitä. Ne ovat vaarallisia, kun niitä ei tehdä aivan oikein, ja useimmat tehtävät voidaan suorittaa muilla tavoin, mutta ne ovat varmasti hyödyllisiä * muutaman kerran, kun ne todella ovat käteviä.
@MichaelKjörling: Niin totta. Vaihdan jatkuvasti upotetun C- ja C # -ohjelmoinnin välillä (jopa toteuttamalla samanlaisen koodin laitteen ja tietokoneen väliseen viestintään) ja niin mahtava kuin C # saattaa olla, nautin silti C: stä niin paljon.
@Michiael: En ole raskas Java-käyttäjä, mutta etkö voi yksinkertaisesti kääri funktiota luokkamenetelmäksi ja tallentaa (osoittimen) kyseiseen luokkaan?
@Wouter Luultavasti voisit. Mielestäni ei ole, että et voi tehdä jotain vastaavaa, vaan se, että todelliset osoittimet voivat olla erittäin hyödyllisiä muutama kerta, kun et voi, tai kun teet saman asian muilla tavoilla, tarvitaan paljon enemmän koodia. En voi ajatella hyvää esimerkkiä pääni yläosasta, mutta sillä on todennäköisesti enemmän tekemistä sen kanssa, että nykyään teen enimmäkseen ohjelmointia siellä, missä tarvetta ei ole tullut esiin. Osoittimet (varsinkin tarkastamattomassa yhteydessä) ovat vaarallisia, ja tunnetusti vaikea saada oikeaksi, mutta * hyvin satunnaisesti *, paljaat osoittimet ovat * juuri * työkalu, jota tarvitset käsillä olevaan tehtävään.
@MichaelKjörling: C #: llä voit käyttää edustajan tyyppisiä muuttujia (erityisesti Func <...> ja Action <...> -tyyppejä) suunnilleen samalla tavalla kuin C käyttää funktion osoittimia. Tämä pätee erityisesti silloin, kun asetat delgaten yhtä staattista menetelmää vastaavaksi. (Ei-staattisissa menetelmissä ne eivät toimi kuten c ++: n osoitin-jäsen-rakenne, vaan pitävät viittausta johonkin tiettyyn esimerkkiin). Jos koodisi toimii täydellä luotettavuudella (kuten työpöytäsovellukset), voit käyttää myös C # -merkkiä käyttämällä raakoja ei-toiminnallisia osoittimia "vaarallisen" koodin kanssa. Javalla puuttuu tarkoituksella molemmat ominaisuudet.
`fp (12)` ei lisää luettavuutta yli `(* fp) (12)`. Niillä on erilainen luettavuus. `(* fp) (12)` muistuttaa lukijaa siitä, että `fp` on osoitin ja muistuttaa myös` fp`-ilmoitusta. Mielestäni tämä tyyli liittyy vanhoihin lähteisiin, kuten X11 sisäisiin osiin, ja K&R C: seen. Yksi mahdollinen syy, miksi se saattaa liittyä K&R C: hen, on se, että ANSI C: ssä on mahdollista ilmoittaa "fp" funktion syntaksilla, jos " fp` on parametri: `int func (int fp (kaksinkertainen)) {}`. K & R C: ssä se olisi ollut `int func (fp) int (* fp) (kaksinkertainen); {...} ".
Saattaa olla syytä keskustella seurauksista, kuinka toiminto-osoittimet toteutetaan paljaalla metallilla olevalla alapäällä.
@Kortuk kysymyksen konteksti on PIC18F46K22, tuskin matalan luokan PIC. Mutta 14-bittisissä ytimissä funktion osoitin ei ole paljon erilainen kuin mikään muu osoitin. 12-bittisessä ytimessä asiat ovat monimutkaisia, mutta epäilen, että joka tapauksessa käytettäisiin funktion osoittimia sirulla, jossa on 2-tasainen pino.
@WoutervanOoijen Monet käyttäjät eivät tiedä, että he saattavat tehdä jotain hyvin hullua. Meillä oli joitain alemman tason laitteita, joilla oli toimintoviitteitä, koska he olivat tehneet sen aiemmin. PIC18: lla on paljon mukavampia asioita, saattaa vain olla syytä laajentaa hieman sisällyttää mikrosirun vaikutukset. Vain ehdotus.
Rev1.0
2013-01-25 15:14:27 UTC
view on stackexchange narkive permalink

Vaikka Woutersin vastaus on ehdottomasti oikea, tämä on ehkä aloittelijoille ystävällisempi ja parempi esimerkki kysymyksestäsi.

  int (* fp) (int) = NULL; int ToimintoA (int x) {return x + x;} int FunktioB (int x) {return x * x;} void Esimerkki (void) {int x = 0; fp = toiminto A; x = fp (3); / * tämän jälkeen x == 6 * / fp = ToimintoB; x = fp (3); / * tämän jälkeen, x == 9 * /}  

Jos ei ole selvää, että funktion osoittimelle on todella määritetty kohdefunktion osoite, on viisasta suorittaa NULL-tarkistus.

  if (fp! = NULL) fp (); / * parametreilla, jos sovellettavissa * /  
+1 nollatarkistukselle, mutta huomaa **, että kääntäjä ei välttämättä takaa, että RAM-osoitteen osoite, jonka "fp" sattuu käyttämään, on alun perin NULL. Teisin `int (* fp) (int) = NULL;` yhdistetyksi ilmoitukseksi ja alustukseksi, jotta voisit olla varma - et halua hypätä johonkin satunnaiseen muistipaikkaan jonkin hölmön arvon vuoksi, joka juuri sattui olemaan siellä. Määritä sitten `fp` kuten` `Esimerkki () '' - toiminnossa.
Kiitos kommentista, lisäsin NULL-alustuksen.
@MichaelKjörling hyvä asia, mutta jos "fp" on "globaali muuttuja" (kuten yllä olevassa koodissa), niin se taataan alustettavaksi arvoon "NULL" (ilman että sitä tarvitsee tehdä nimenomaisesti).


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...