wskaznik do funkcji

Mar 15, 2005 25 Replies

Witam



Pisze w Keil uVision3 prosty programik dla 89c2051 i oto co mnie wkurza lub robie cos ¼le :



zadeklarowalem :



typedef void (*WYN)(unsigned char*);



void Przelicz(unsigned char* nazwa){



//tu pusto poki co



}


void Oblicz(unsigned char adres,unsigned char* nap, WYN licz){ unsigned char bufor[5]; //tutaj zmienna adres = 0x80 czyli oki



licz(bufor);



//tutaj adres = 0. rowniez nap =0 .



}

main(){



....... Oblicz(0x80,napis,Przelicz);



}

Pytanie sie pojawia czemu on zamazuje te dane podczas wykonywania niczego. Sposob skoku do funkcji sie zmienia przy takim adresowaniu ale wedlug mnie powinno byc oki. Chyba ze robie cos zle, a moge robic bo 1 raz takiego adresowania uzywam.



dzieki za porady ynio


Ponizej kompletny przyklad. Tak jakby wywolujac funkcje "funckja(bufor)" on jakby zwalnial pamiec dla funkcji "dzialaj"; Czy to jest normalne ???

ynio

typedef void (*WYN)(unsigned char*);

code unsigned char napis[]="dupa wolowa";

void Przelicz(unsigned char* nap){

}

void dzialaj(unsigned char adres,unsigned char* wysw,WYN funkcja){

unsigned char bufor[5];

//tu adres = 0x80 funkcja(bufor); //tu juz adres = 0

adres= adres + 1;

}

main(){

while(1){ dzialaj(0x80,napis,Przelicz); }

}

To jest zapisane poprawnie, ale nie ma żadnego sensu - "wysw" jest nieużywany, "adres" tak naprawdę również jest nieużywany, "bufor" jest niezainicjalizowany, a jak mniemam powinien (chociaż nie musi) być. Najprawdopodobniej kompilator zauważył te niekonsekwencje i dokonał odpowiednich optymalizacji.

Regards, /J.D.

No wlasnie w tym przypadku to tak.Ja to napisalem przykladowo zeby nie zaczerniac przykladu. W normlanym programie wszystko jest uzywane, a mimo to zmienne sa zerowane, naotmiast jesli wywolam funkcje jawnie to wszystko w porzadku Sprawdze innym kompilatorem. ynio

Tez mi sie tak wydaje.

Nie bardzo mial prawo - musialby bardzo globalnie patrzec zeby moc to zrobic. A przy takim zapisie to skad ma wiedziec ze mniejszy fragment nic nie robi ?

Podeslij wydruk assemblerowy tego przykladu, moze dodajac putc(bufor[0]) przed i po wywolaniu [printf bedzie za dlugi]. Moze wtedy cos zobaczymy podejrzanego.

Moze blad w kompilatorze, moze trzeba mu dorzucic jakies slowa kluczowe ?

J.

Skubany kompilator optymalizowal. Dalem dyrektywy przed funkcja i po funkcji :

#pragma ot(1,size)

funkcja // ktora sporo dziala

#pragma ot(9,size)

I co ciekawe program troche zwiekszyl objetosc ale wszystko gra i huczy. :) Co o tym sadzicie ?

ynio

Ale tego nie powinien bardzo optymalizowac ..

J.

A tak apropos - moze to nie problem z wywolywaniem funkcji, tylko w tej Przelicz wychodziles poza zakres bufora ?

J.

On Wed, 16 Mar 2005 14:40:59 +0100, "ynio" snipped-for-privacy@poczta.onet.pl> wrote: [.....]

Sądzimy że to normalka. Ale skoro kompilator zoptymalizował kawałek kodu czego wg. Ciebie nie powinien był robić, to jest prawie pewne, że ów kawałek kodu jest do bani. Nie wiem czego konkretnie oczekujesz, ale jeśli chcesz aby kompilator za bardzo nie przesadzał z optymalizacją, to możesz używać modyfikatora "volatile" do deklaracji niektórych zmiennych. IMO daje lepszą kontrolę nad kodem niż nieprzenośne pragmy czy też opcje kompilatora.

Regards, /J.D.

IMO jak najbardziej powinien. Np. wyrażenie adres = adres + 1; umieszczone na końcu funkcji nie ma żadnego skutku (przy deklaracji zmiennej adres takiej jak w przykładzie). Więc nadaje się do wywalenia, tzn. optymalizacji. :-) Dobry kompilator, czyli gcc, :-) przy optymalizacji O3 wogóle wywali wywołanie funkcji działaj i z main-a od razu zawoła funkcję Przelicz.

Regards, /J.D.

No wlasnie nie, specjalnie dawalem spory buforek. No nic w razie to taki manewr pomaga.

W koncu i tak to rozwiazalem wszystko nie uzywajac wskaznikow do funkcji. Teraz ladnie smiga i nie trzeba zmniejszac optym.

Pozdr ynio

No wlasnie nie.

Pusta funkcje Przelicz moze zamienic na jednego ret. adres++ moze wywalic, ale funkcja(bufor) juz nie - bo nie wie co jest w zmiennej "funkcja". Tzn moglby wiedziec, ale to juz by chyba za duzo optymalizacji bylo :-)

Owszem, moglby w ogole parametr "adres" potraktowac jako przestrzen robocza bo nieuzywany ... ale skoro ynio stwierdzil ze sie zmienia .. to chyba jednak uzyl.

No chyba ze ynio stwierdzil to debuggerem, a kompilator przydzielil tej zmiennej rejestr i skoro nie uzywana to nie uznal za sensowne zachowywac na czas wywolania *funkcja.

Stanowczo trzeba zajrzec w assemblerka.

J.

Analizowalem sobie znowu i faktycznie gdy cos sie robi ze zmienna to przetrzymuje. Ale w moim przypadku tez robilem, adres bezposrednio przekazywalem do innej funkcji, tak samo jak adresy do buforow. No nic powstal ciekawy temat:) W razie gdy cos nie dziala nalezy wylaczyc optymalizacje i zobaczyc czy to nie taka przyczyna :)

Pozdrawiam ynio

Dzieki, bede sie staral. Prawdopodobnie cos gdzies chrzanilem, teraz juz to przerobilem zupelnie inaczej i jest git. Nie bede tu sie bronil ale w c pod 8051 zaczalem od tygodnia :) kiedys sporo w asemblerze.

A z innej beczki mam takie wyrazenie : (3600*z) / x.

Z tego x przyjmuje wartosci 1-200. Chodzi oto ze zrobilem to w taki sposob:

x i z to unsigned int.

z = [0,132]

unsigned long temp; temp = 3600* (unsigned long)z; temp = temp/x;

Wszystko dziala, tylko to cholernie nie optymalny kawalek, bo zajmuje sporo i wykonuje sie ok 100us przy 12MHz. Czy znacie jakies sztuczki na takie operacje? wiem ze jakby bylo dzielenie przez potege dwójki to spoko, mozna przesuwac bity.

dzieki ynio

On Wed, 16 Mar 2005 19:02:36 +0100, "ynio" snipped-for-privacy@poczta.onet.pl> wrote: [.....]

Jeśli to ma być szybkie, to sam zaimplementuj w assemblerze mnożenie i dzielenie liczb wielobajtowych. Możesz też stablicowac wartość wyrażenia 3600*z (133 liczby czterobajtowe) albo nawet całego wyrażenia jeśli masz dużo pamięci programu. Możesz też użyć taniego mikrokontrolera 32-bitowego i zapomnieć o takich problemach. :-)

Regads, /J.D.

No i kompilator (gcc -O3) robi to sprytnie - generuje poprawne i zoptymalizowane ciało funkcji działaj() (bo być może będzie ona wołana z innego modułu programu), ale w main-ie woła od razu Przelicz(). Nie sprawdzałem tego, ale wydaje się być całkiem naturalne, że gdyby działaj() było zadeklarowane z modyfikatorem static, to kompilator nie wygenerowałby kodu dla tej funkcji.

Gcc 3.4.0 dla ix86 z właczoną optymalizacją O2 lub mniejszą tego nie wie, ale z O3 już wie. :-)

No właśnie zmnienia się dlatego, że najprawdopodobniej miejsce przez które została przekazana wartość adres (czyli, w zależności od calling convention, rejestr lub komórka pamięci na stosie) zostało użyte jako owa "przstrzeń robocza", a konkretnie jako miejsce przez które przekazuje się z kolei argument do funkcji funkcja(), czyli po prostu wskaźnik (adres) tablicy char-ów.

Ja to jestem praktycznie pewny, że stwierdził to na podstawie wskazań symulatora/debuggera. :-)

Oczywiście. Tak też zrobiłem, aczkolwiek dla ix86. :-)

Regards, /J.D.

U¿ytkownik "Jan Dubiec" snipped-for-privacy@SPAMTRAP.slackware.pl> napisa³ w wiadomo¶ci news: snipped-for-privacy@hs001.slackware.pl...

Haha :) 32 botowy procek, spoko. Na razie dzialam na malutkim 89c2051 i niech sie meczy z dzieleniem:) Tablica raczej nie wchodzi w gre, bo to dzielenie najdluzsze, 2kb pamieci prawie wykorzystana, i dwie zmienne w dzialaniu :) no nic dzieki sliczne

ynio

Wstawka assemblerowa ? Mnozenie longa [eee - 24 bit starcza] przez 8 bit jest zgrabne, dzielenie przez 8 bit tez. Hm .. a moze kompilator o tym wie ?

J.

On Thu, 17 Mar 2005 22:58:12 +0100, J.F. <jfox snipped-for-privacy@poczta.onet.pl> wrote: [.....]

Nie sądzę. Dlatego sugerowałem napisanie własnych funkcji w assemblerze.

Regards, /J.D.

U¿ytkownik "Jan Dubiec" snipped-for-privacy@SPAMTRAP.slackware.pl> napisa³ w wiadomo¶ci news: snipped-for-privacy@hs001.slackware.pl...

a jak sie azbarac do takiego dzielenia? ynio

Join the Discussion

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

Didn't find your answer?

Ask the community — no account required