Gå til innhold

Led meg ikke inn i goto-fristelsen


Anbefalte innlegg

Skriver på noe hardware-programvare, og da er det fryktelig mye som går galt. I prinsippet vil koden, som bruker I/O-hardware, var en rekke med kodelinjer. Men for hver linje kan noe gå galt, og i så tilfelle skal prosedyren avbrytes. En fristende løsning er:

SOME_REG = val;
if (STATUS != 0) goto Disaster;
SOME_OTHER_REG = val2;
if (STATUS != 0) goto Disaster;
[...]
Disaster:
[...]

Men pga. "goto"s lite flatterende rykte vil jeg helst unngå det. Et alternativ er:

while (1) {
SOME_REG = val;
if (STATUS != 0) break;
SOME_OTHER_REG = val2;
if (STATUS != 0) break;
[...]

Men jeg liker ikke den så godt heller.

 

Noen forslag? Programmet skal kjøre på mikrokontroller, så jeg har ikke all verdens minne og prosessorkraft. Og eneste kompilator er dessverre C. (Ikke noe smarte greier i C++ mao.)

Lenke til kommentar
Videoannonse
Annonse

Hehe, her kunne du ha brukt C++ exceptions :D

Uansett, kan du ikke bare lage en funksjon som gjør sjekke for deg, og dersom noe går galt, kaller en avslutningsfunksjon?

void CheckStatus(int status) {
if(status != 0) {
  kallenellerannenfunksjoneher();
  exit(0); //avslutt med feil
 }
}

SOME_REG = val;
CheckStatus(STATUS);
SOME_OTHER_REG = val2;
CheckStatus(STATUS);

Vet ikke om dette gjør saken noe bedre...

Lenke til kommentar

Det er vanlig i C å bruke goto for feilbehandling. Selv har jeg for vane å skrive makroer som jeg enkapsulerer funksjonskall i, hvis funksjonskallet resulterer i en feilkode hoppes det automatisk til en feilhåndteringsblokk. Finfint når man ikke har tilgang til exceptions, og har en standard feilhåndteringssekvens (frigjøre ressurser f.eks).

 

Hvis det høres tvilsomt ut, les selv denne linken fra Pythons API-manual: Exceptions. Jeg tror ikke noen vil påstå at Python har grisete mekanismer for feilhåndtering, men slik gjøres det altså i C.

Endret av A_N_K
Lenke til kommentar

Forsøker meg på denne jeg (i pseudokode):

loop forever
 case Step is
   when 1: Do_Action_1();
   when 2: Do_Action_2();
   [...]
 end case;
 
 if Status_Ok() then
   Increment(Step);
 else
   exit loop;
 end if;
end loop;

Det er som sagt en mikrokontroller-applikasjon. Så målet er ikke å behandle feil, men å la vær å bruke ressurser på noe som har gått galt. Step-variabelen kan benyttes til å avgjøre om operasjonen var vellykket, i motsatt fall forsøke på nytt om nødvendig.

Lenke til kommentar
Hvis målet er å spare ressurser så er det kanskje en idé å ikke feilsjekke hvor vært eneste steg, men bare sjekke det til slutten. Om det er mulig da?

 

Ellers er, som nevnt av andre, exceptions C++ måten å håndtere feil på.

5236494[/snapback]

Man sjekker feil ved å lese et register, og dette blir overskrevet hver gang man bruker IO-interface'et. Så det er ikke mulig uten å risikere en del ting, f.eks. noe går galt uten at man vet om det, kretsen henger, osv.

 

Når det gjelder exceptions er det kompilatoren det står på, ikke med. Er ikke så mye å velge i mellom for 8051.

Lenke til kommentar

Så vidt jeg vet skal bruk av goto være forholdsvis lett å optimere for kompilatoren (*friste*). Vet ikke hvordan det er med denne kompilatoren, men én fordel med å definere generelle feilsjekkings/håndterings-makroer med GCC er at feilsjekkingen kan optimeres via et direktiv (husker ikke akkurat hvilket) som sier hvilken boolsk verdi som forventes (dvs at man forventer ikke feil).

Lenke til kommentar

Goto er veldig enkelt, optimaliserng er helt unødvendig da det bare er et kall for prosessoren uansett, grunnen til at en ikke bruker goto er fordi mye goto vil gjøre programmet vanskelig å lese hvis det er fler en én, og til feilbehandling er det vel ypperlig i dette tilfellet.

 

break og return er ikke helt stuerent det heller, fordi programmet ikke "flyter", men det driter ihvertfall jeg i, hvis resultatet er færre løkker og generelt færre linjer med kode, ikke lag koden mer komplisert en den trenger, i de aller fleste tilfeller er ikke goto en bra løsning, men det ville jeg si er tilfellet her, men hvis du ikke vil bruke goto, kan du også lage en macro som ser slik ut

#define CHECK_ERROR() if(STATUS) DoErrorHandling(STATUS); return

e.l.

Lenke til kommentar

Personlig må jeg si at jeg foretrekker while(1) { break; } -varianten hvis det ikke er passende med exceptions. Men det er vel smak og behag. I sanntidsprogrammering er while-varianten mye brukt.

 

Eneste unntaket for bruk av goto slik jeg ser det, er typiske cleanup-blokker i slutten av rene c-funksjoner. Men i C++ bruker vi gjerne auto_ptr og lignende ikke bare for å gjøre det enklere, men også gjøre koden exception-safe.

Lenke til kommentar
Er ikke premisset her at det er kun tilgang til en C-kompilator? Ser ikke meningen med å diskutere exceptions (med mindre man ønsker å implementere en ekvivalent i C).

5241784[/snapback]

 

Oopps.. så ikke det. Må nok lese litt mer nøye neste gang :). Hender det går litt fort i svingene her ...

Lenke til kommentar
Hvis målet er å spare ressurser så er det kanskje en idé å ikke feilsjekke hvor vært eneste steg, men bare sjekke det til slutten. Om det er mulig da?

5236494[/snapback]

Man sjekker feil ved å lese et register, og dette blir overskrevet hver gang man bruker IO-interface'et. Så det er ikke mulig uten å risikere en del ting, f.eks. noe går galt uten at man vet om det, kretsen henger, osv.

5236545[/snapback]

 

Ok.. her er et forslag. Dersom det ikke er nødvendig å håndtere feilen, bare detektere feilen, og statusregisteret et null dersom alt fungerer, så ville jeg rett og slett bare hatt en sjekkvariabel, og etter hver operasjon rett og slett adderte statusregisteret til denne. Om sjekkvariabelen så på slutten er lik null, så vet du at alt har gått bra.

 

En mulig snag her er om summen av flere feilkoder kan bli null (f.x via overflow).

 

edit:

unsigned char err=0;
SOME_REG = val;
err+=STATUS;
SOME_OTHER_REG = val2;
err+=STATUS;
[...]
if (err!=0) {  disaster }
[...]

Endret av JBlack
Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...