[avr-gcc] adres instrukcji

Mar 01, 2007 25 Replies

Mam jak sobie taki problem:



etykietaa: instrukcja1a;instrukcja2a;instrukcja3a; etykietab: instrukcja1b;instrukcja2b;instrukcja3b; etykietac: instrukcja1c;instrukcja2c;instrukcja3c;



no mogê sobie skoczyæ tam rozkazem goto etykieta



Fajnie, ale ja potrzebujê zrobiæ sobie tabelê i skakaæ pod odpowiednie, zale¿ne od danej sytuacji adresy. Chcia³bym zrobiæ co¶ takiego:



void * adresy[]={etykietaa,etykietab,etykietac};



To jednak nie dzia³a, bo etykiety s± jakim¶ dziwnym tworem (nie adresem) i rozmawiaj± tylko z goto.


Pytanie jest takie: W jaki sposób pozyskaæ adres pewnego miejsca w programie w momencie kompilacji?


Patryk Sielski napisał(a):

Z tego co mnie uczyli, to nie powinno się używać instrukcji goto w takim języku jakim jest C. Nie można tego rozwiązać inaczej? Konstrukcja "switch() + case:"?

Virus_7 <virus_7@wytnij_to.o2.pl> pisze:

Mo¿na, ale wymagaæ to bêdzie z 50MHz i 30 kB kodu i ¼ród³a trzeba bêdzie wygenerowaæ.

Pytanie pozostaje aktualne.

Użyć funkcji ?

inline void etykietaA(void) {instrukcja1a;instrukcja2a;instrukcja3a;} inline void etykietaB(void) {instrukcja1b;instrukcja2b;instrukcja3b;} inline void etykietaC(void) {instrukcja1c;instrukcja2c;instrukcja3c;}

void (*funkcje[])(void)={etykietaA, etykietaB, etykietaC};

int main(void) { (*funkcje[0])(); (*funkcje[1])(); (*funkcje[2])(); }

Albo bardziej podobne do działania goto :

inline void etykietaC(void) {instrukcja1c;instrukcja2c;instrukcja3c;} inline void etykietaB(void) {instrukcja1b;instrukcja2b;instrukcja3b;etykietaC();} inline void etykietaA(void) {instrukcja1a;instrukcja2a;instrukcja3a;etykietaB();}

void (*funkcje[])(void)={etykietaA, etykietaB, etykietaC};

Mam nadzieję, że kompilator też mnie zrozumie.

W dniu 01-03-2007 20:35, Virus_7 napisał:

A ja uważam, że w pewnych wypadkach (na przykład wychodzenie ze złożonych zagnieżdżonych pętli/innych struktur) GOTO jest niezastąpione.

U¿ytkownik "Patryk Sielski" snipped-for-privacy@elka-usun.pw.edu.pl> napisa³ w wiadomo¶ci news:b03d6$45e70d28$57ceab2d$ snipped-for-privacy@news.chello.pl...

Z ciekawo¶ci zapytam: mo¿esz trochê przybli¿yæ problem? Je¿eli switch - case (który robi w³a¶nie to co chcesz uzyskaæ - w zale¿no¶ci od kompilatora (a raczej jego zgodno¶ci z ansi) mo¿na naprawdê cuda tym uzyskaæ, poszukaj czego¶ nt. mechanizmu duffy'ego) i wska¼niki do funkcji nie s± w stanie za³atwiæ sprawy, to problem na pewno jest ciekawy. pzdr, marcin

Spinacz biurowy, Virus_7 <virus_7@wytnij_to.o2.pl>!

Źle uczyli. Są sytuacje, w których goto w C jest najbardziej przejrzyste (głównie cleanup). Np.

if (warunek1) goto err1;

alloc_zasob_1(); if (warunek3) goto err2;

alloc_zasob_2(); if (warunek3) goto err3;

return 0;

err3: free_zasob_2(); err2: free_zasob_1(); err1: return -1;

snipped-for-privacy@tlen.pl pisze:

Tak, to jest rozwi±zanie, aczkolwiek ma pewne wady, poniewa¿ nie mogê wskoczyæ w ¶rodek funkcji na przyk³ad

etyk1: bla(); etyk2: bla2(); etyk3: bla(); return;

marcinuh snipped-for-privacy@o2.pl pisze:

OK, jest to interpreter pewnych protoko³ów. Protoko³ów jest kilka. Rozkazów do wykonania-full.

W tej chwili jest tak:

switch (rozkaz)

case 'A' : wykonanie rozkazu 'A';break; case 'B' : wykonanie rozkazu 'B';break; case 'C' : wykonanie rozkazu 'C';break; case 'D' : wykonanie rozkazu 'D'; // i jedziemy dalej wykonuj±c rozkaz E case 'E' : wykonanie rozkazu 'E';break;

wady rozwi±zania:

1) na ka¿dy protokó³ muszê mieæ osobnego switcha 2) ten switch optymalizuje siê tak dziwnie, ¿e argument porównywany jest kolejno z ka¿dymi casem. Na ka¿dy case jest porównanie i skok i tak dalej. Trwa to trochê. O wiele szybciej by³oby zrobiæ tabelê i po prostu jechaæ po tabeli, jak siê znajdzie - skok.

Funkcje s± pewnym rozwi±zaniem, ale spowoduje to zbyt du¿e przypisywanie kodu, tak wiêc szukam czego¶, ¿eby tylko te 'case' zamieniæ na jakie¶ etykiety.

Jechac po tabeli, to tez porownania przeciez. To juz lepszy by byl ten switch na oko patrzac.

Albo przepisac ten kawalek jako wstawke assemblerową.

el es

Lukasz Sokol <el snipped-for-privacy@poczta.onet.pl> pisze:

No nie, bo generuje du¿o kodu.

No to wstawka assemblerowa. Poszukaj, widzialem w jakims przykladzie, jak z pod wstawki wywolywac procedure zdefiniowaną gdzies indziej w c.

el es

U¿ytkownik "Patryk Sielski" snipped-for-privacy@elka-usun.pw.edu.pl> napisa³ w wiadomo¶ci news:28f1c$45e7634b$57ceab2d$ snipped-for-privacy@news.chello.pl...

Hmm, a mo¿esz wrzuciæ przyk³ad jak siê w AVR-GCC kompiluje case? w mcc18 to jest xor dla porównania i skok - trudno co¶ mniejszego i szybszego by by³o. Rozumiem o co Ci chodzi, chcia³by¶ np. rozkazu u¿yæ jako indeksu w tablicy, tablice by³yby tworzone po jednej dla kazdego protoko³u. Proponujê tablice wska¼ników do funkcji, je¿eli zadeklarujesz je jako void od(void), to nie masz praktycznie ¿adnego narzutu w kodzie i czasie na wywo³anie i powrót z funkcji - nie trzeba pchaæ na stos parametrów ani zwracaæ warto¶ci... W takich sytuacjach zawsze staram siê pamiêtaæ o maksymie wyczytanej w ksi±¿ce na temat programowania kernela - "do not try to be too smart" ;-). pzdr, marcin

Lukasz Sokol <el snipped-for-privacy@poczta.onet.pl> pisze:

To ja potrafiê, ale jak pozyskaæ ten adres????? Ale nie funkcji, ale pewnego miejsca w programie.

marcinuh snipped-for-privacy@o2.pl pisze:

b8e: c7 36 cpi r28, 0x67 ; 103 b90: d1 05 cpc r29, r1 b92: a4 f4 brge .+40 ; 0xbbc b94: c1 36 cpi r28, 0x61 ; 97 b96: d1 05 cpc r29, r1 b98: 54 f5 brge .+84 ; 0xbee b9a: ca 35 cpi r28, 0x5A ; 90 b9c: d1 05 cpc r29, r1 b9e: 09 f4 brne .+2 ; 0xba2

To, ¿eby to przepisaæ jako funkcje ju¿ my¶la³em, alke to strasznie du¿o roboty jest i trzeba nieco pozmieniaæ te funkcje, bo czasem jeden rozkaz wykonuje te¿ i inny, ktgóry jest dalej.

BTW: Chyba zapytam za dwa tygodznie, jak w±tek bêdzie ¶wie¿y i zaznaczê, ¿e nie chodzi i o przepisanie tego na funkcjê, bo z uporem godnym lepszje sprawy proponuje mi sie te funkcje mimo, ze napisalem, ¿e to ostateczno¶æ.

Jesli problemem jest dlugie "wykonanie rozkazu" to mozesz wstepnie transkodowac do jednego protokolu..

Kompilator powinien ocenic i zoptymalizowac. Czesto mu wyjdzie ze tak jak powyzej jest najlepiej.

Ogolnie C nie przewiduje.

J.

Ogólnie to owszem. Ale gcc posiada rozszerzenie, które w tym przypadku może się nadać - skoki wyliczane. Wygląda to mniej więcej tak:

void *gdzie;

gdzie = &&etykieta;

...

if (costam) goto *gdzie;

...

etykieta: /* tu dalszy ciag programu */

Nie żeby kod miał przez to ładniej wyglądać, ale do interpretera może się nadać.

Szeluś

In the darkest hour on Thu, 01 Mar 2007 20:35:46 +0100, Virus_7 <virus_7@WYTNIJ_TO.o2.pl> screamed:

Źle uczyli. Przydaje się min. w sytuacji gdy chcesz zrobić wielopoziomowy break lub nie chcesz dublować pewnych instrukcji w instukcjach warunkowych obsługujących błąd w funkcji. To oczywiście tylko niektóre z przykładów kiedy wolę goto.

snipped-for-privacy@googlemail.com pisze:

MISZCZ!

Dziêki!

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required