C nestede brytere: ytre bryter saks inne indre bryter

stemmer
1

Jeg legger coroutine støtte til tolk jeg skriver, og jeg har lyst til å gjøre noe sånt som følgende:

typedef enum {
    bar_stuff,
    bar_other
    } Bar;

typedef enum {
    foo_error=-1,
    foo_none=0,
    foo_again
    } Foo_state;

Foo_state do_foo(Bar bar,Foo_state foo)
    {
    switch(foo)
        {
        case foo_none: //start
        switch(bar)
            {
            case bar_stuff:
                //do stuff
                return foo_none;
            case bar_other:
                //do other stuff
                return foo_again;
                case foo_again: //!! this doesn't work
                    /* edit: this is supposed to be a case of
                     *     switch(foo), not switch(bar)
                     */
                //do more other stuff
                return foo_none;
            default:
                //stuff
                return foo_none;
            }
        default:
            //fail
            return foo_error;
        }
    }

Selvfølgelig er dette dosn't arbeid (jeg får duplikat tilfelle verdi, er alternativ sannsynligvis udefinert atferd / segfault). Jeg kunne skrive bryteren (bar) som en if / else if / else-kjeden, men jeg hadde håpet det var en bedre måte.

Jeg bruker gcc hvis det gjør en forskjell.

Redigere:

Følgende ville fungere, men ville være et mareritt å vedlikeholde:

Foo_state do_foo2(Bar bar,Foo_state foo)
    {
    switch(foo)
        {
        case foo_none:  goto case_foo_none;
        case foo_again: goto case_foo_again;
        default:
            //fail
            return foo_error;
        }
    case_foo_none: //start
    switch(bar)
        {
        case bar_stuff:
            //do stuff
            return foo_none;
        case bar_other:
            //do other stuff
            return foo_again;
            case_foo_again:
            //do more other stuff
            return foo_none;
        default:
            //stuff
            return foo_none;
        }
    }

Edit 2:

Vel, dette ser ikke ut til å være noe som ga den tidligere nevnte 'bedre måte', så jeg vil gjerne vite om noen forutser et problem med å skrive det slik:

Foo_state do_foo3(Bar bar,Foo_state foo)
    {
    switch(foo)
        {
        case foo_none: //start
        if(bar == bar_stuff)
            {
            printf(do stuff\n);
            return foo_none;
            }
        else if(bar == bar_other)
            {
            printf(do other stuff\n);
            return foo_again;
            case foo_again: //continue
            printf(do more other stuff\n);
            return foo_none;
            }
        else
            {
            printf(stuff\n);
            return foo_none;
            }
        default:
            //fail
            return foo_error;
        }
    }

Problemet jeg ser med dette mangler en bar_ * verdi (siden det er flere funksjoner som dette, og noen av de enums har dusinvis av verdier), men jeg antar at en test script for at skal fungere ...

Publisert på 30/12/2009 klokken 01:05
kilden bruker
På andre språk...                            


4 svar

stemmer
4

Hm ... bruke en ekvivalent av et Karnaugh Kart for å forenkle logikk og gjøre alt med

if (cond1 && cond2) {
  doX();
  return;
}
if (cond3 && cond4) {
  doY();
  return;
}
// Sometimes you can take shortcuts
if (cond5) {
   doZ();
} else {
   doW();
}
return;

Denne koden er lesbar. Nestede ting er best unngås hvis mulig.

Kontrollere de enkleste forholdene først vil gjøre funksjonen enklere.

I ditt tilfelle starte med:

Foo_state do_foo2(Bar bar,Foo_state foo) {
  if (foo != foo_none && foo != foo_again) {
    return foo_error;
  }
  ...

  if (foo == foo_none) {
    ...
  }
  // Implicit Else
  ...
Svarte 30/12/2009 kl. 01:10
kilden bruker

stemmer
1

En enkel løsning ville være å endre verdiene i bar_ enum slik at de er unike med hensyn til foo_ enum. Det løser ikke det faktum, men at koden er forvirrende. Hvorfor vil du se etter en foo_ verdi innsiden av bar_ bryter uttalelse? Syntaktisk, er det gyldig (så lenge verdiene er unik), men det er dårlig koding.

Svarte 30/12/2009 kl. 01:16
kilden bruker

stemmer
6

Man kan også bare sette {} inne i hvert tilfelle: setningen
uten at hele saken stabelen blir evaluert som en enkelt enhet, slik at ingen variabler kan defineres innenfor et tilfelle:

Men ved å sette

 case blah:
 {
  // do stuff
 }
 break;

Du kan sette anythign du ønsker inne i saken uttalelse.

Svarte 30/12/2009 kl. 01:31
kilden bruker

stemmer
0

Ok, virker det som koden din gjør dette:

bar \ foo   foo_none                          foo_again                             other
bar_stuff   doStuff, return foo_none          do more other stuff, return foo_none  return foo_error
bar_other   do other stuff, return foo_again  do more other stuff, return foo_none  return foo_error
other       stuff, return foo_none            do more other stuff, return foo_none  return foo_error

Dette er hva jeg mente med en Karnaugh kart. Nå, her er den enkleste gjennomføringen:

Foo_state do_foo2(Bar bar,Foo_state foo) {
  if (foo == foo_again) {
    // do more stuff
    return foo_none;
  }
  if (foo != foo_none) { // other
    return foo_error;
  }
  // foo_none
  if (bar == bar_stuff) {
    // do stuff
    return foo_none;
  }
  if (bar == bar_other) {
    // do other stuff
    return foo_again;
  }
  // At this point bar = other

  // stuff
  return foo_none;
}

Jeg tror dette gjør det samme som koden din, men ikke bruker brytere og GOTO. Du kan fylle ut en tabell med resultatet, og du kan også sette begge implementeringer gjennom en enhet tester for å sikre at de gjør det samme for alle innganger.

Svarte 30/12/2009 kl. 12:26
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more