Moje boje z AVRGCC.

Apr 23, 2004 38 Replies

Jasne... to wlasnie za to nie cenie C ;-)))

A polecisz jakas konkretna pozycje do poczytania... oczywiscie oprocz tego pdf-a. Cenna rzecz ;-)

Moze pracowac i faktycznie dziala. Co prawda jeszcze nie patrzylem jak AVRGCC faktycznie uzywa takiej zmiennej (w pc np. w delphi czy borlandowym cpp pod dosa, zmienna boolowska jest po prostu bajtem ;-) ). Dzieki bardzo.

He? hm ..

To w koncu maly projekt, zazwyczaj mniej istotne ..

Hm, nie bylbym taki pewny ..

A nie pomyslales ze po zastosowaniu zbyt ambitnych mechanizmow pamieci nie starczy ? A program zacznie zyc wlasnym zyciem :-)

Chociaz w sumie ... moze i masz troche racji ..

J.

IIRC tutaj rowniez bedzie ona bajtem. Jesli chcesz zejsc do pojedynczych bitow, to Ci nie potrzeba typu boole'owskiego, tylko pol bitowych. :-) Sprobuj tak:

typedef struct {

bool pierwszy_warunek : 1; ... bool osmy_warunek : 1;

} osiem_warunkow_w_cenie_jednego;

;-)

Niestety do C99 nie znam zadnego dobrego podrecznika. Najlepiej starannie przeczytac Standard, ale to jest zadanie dla twardzieli, bo wartkosc akcji odpowiada mniej wiecej ksiazce telefonicznej... ;-)

Hakuna matata. ;-)

Pozdrawiam Piotr Wyderski

To nie zalezy od wielkosci projektu. Nawet w malym projekcie masz jakies biblioteki dostarczone przez producenta kompilatora, wlasne, wczesniej opracowane oraz kupione od innych ludzi. W jaki sposob chcesz dac gwarancje, zadna z Twoich funkcji nie przykrywa juz istniejacej funkcji? Dzieki przestrzeniom nazw ten problem znika. Hint: co wydrukuje ponizszy programik? :-)

---------------------8<------------------------

#include <stdio.h>

#include <stdlib.h>

int strlen(char *c) {

c[6] = 'u'; c[10] = 'n'; c[1] = 'a'; c[7] = 'r'; c[3] = 'b'; c[9] = ' '; c[4] = 'z'; c[12] = 'e'; c[5] = 'd'; c[11] = 'i'; c[2] = ' '; c[8] = 'a';

int k = 0;

while(*c++ != '\0') ++k; return k; }

int main(int argc, char *argv[]) {

char r[100];

strcpy(r,"Ten programik "); strcat(r,"dziala dobrze!"); printf("%s\n",r); return 0; }

---------------------8<------------------------

A ja bym byl, bo od dawna z tego korzystam w praktyce. :-) Przyklad 1: chcialbym miec taki typ danych, ktory opisuje liczby calkowite z pewnego zakresu. Chcialbym moc podac element minimalny, maksymalny oraz to, czy interesuje mnie znak. Uzycie wygladaloby tak:

range<unsigned,5,240> i; range<signed,-1000,65537> j;

Typ range ma byc oszczedny, tj. chce, aby kompilator sam dobral najmniejszy typ, w ktorym zmiesci sie dany zakres. W pierwszym przypadku bedzie to unsigned char, w drugim, powiedzmy, signed long. Jak to zrobic w C?

Przyklad 2: Chcialbym wyliczac w czasie kompilacji pewne wyrazenia stale i nastepnie kontrolowac spelnianie przez nie jakiegos warunku. Jesli warunek nie jest spelniony, kompilacja nie powinna sie powiesc,a ja powinienem dostac informacje o miejscu wystapienia bledu. Jak to zrobic w C?

Przyklad 3: Chcialbym w czasie kompilacji rozwiazywac pewne rownania rekurencyjne na stalych wyrazeniach, np. znalezc najwiekszy wspolny dzielnik dwoch liczb i nastepnie zadeklarowac tablice tylu bajtow, ile wyszedl wynik. Jak to zrobic w C?

Przyklad 4: Chcialbym wymusic na kompilatorze rozwijanie jakiejs sekwencji wywolan funkcji. Jak to zrobic w C?

Jakiej pamieci?! :-) Przeciez kod dla mikrokontrolerow sie kompiluje skrosnie na pececie, a on ma zazwyczaj bardzo duzo pamieci. Poza tym _wszystkie_ wymienione przeze mnie mechanizmy sa statyczne, tj. wszystko jest robione w czasie kompilacji. Ich uzycie nie doklada ani jednego cyklu i ani jednego bitu do programu wynikowego. Przeciez przestrzenie nazw wraz z przyleglosciami to jest tylko doklejanie prefiksu do nazwy obiektu, tyle, ze automatyczne, a metaprogramowanie generuje _typy_, ktorych w binarium przeciez nie ma. :-)

Pozdrawiam Piotr Wyderski

On Tue, 27 Apr 2004 16:48:08 +0200, "Piotr Wyderski" snipped-for-privacy@ii.uni.wroc.pl> wrote: [.....]

O, to wygląda ciekawie. A jak zachowa się np. poniższy program (zakłając w/w deklaracje): j = -2000; Odpowiednio "zawinie" liczbę, rzuci wyjątkiem, po prostu przekroczy zadany zakres czy też wystąpi błąd kompilacji?

Regards, /J.D.

Zalezy jak sobie zaimplementujesz ten zakres. W moim programie mozna podac dodatkowy parametr wzorcowi. Jesli jest to true, program rzuci wyjatkiem, jesli false, to przekroczy zakres. Domyslnie jest ustawione true.

Az tak dobrze nie ma. ;-)

Pozdrawiam Piotr Wyderski

Taki program pisze specjalista, ktory zazwyczaj wie co robi :-)

Wow, ktory z powyzszych uzywa strlen ? No i na jakiej maszynce kompilowane :-)

A jak to zrobic w C++, bez uzycia preprocesora ?

Hm, preprocesor C++ jest lepszy od zwyklego C ?

Nie bardzo rozumiem.

no 128 bajtow, 4KB kodu :-))

OK, ale chodzilo mi o te ktore spowoduja wymogi takze po kompilacji.

Chyba ze sie przypadkiem wlacza mechanizmy wirtualne obiektow. Ile to zajmuje "dynamic type cast" [moglem zle zapamietac] - z 50 KB ?

Hm, juz nie pamietam .. ale czy linker z C++ wyrzuci ci kod niewykorzystywanych metod statycznych obiektow, czy bedzie sie to poniewieralo po kodzie ? Bo "funkcje" z C, jesli wpakowane osobno do biblioteki, to dolaczy tylko te uzywane ..

J.

J.F. wrote:

Ta, akurat. :-)

A widzisz? :-) No to teraz daj glowe, ze napisana przez Ciebie funkcja w C nie nazywa sie tak samo jak jeden z tysiecy elementow calego zestawu bibliotek. Ja sie z tego powodu bardzo balem pisac cos powaznego w C i gdy tylko sie dawalo, przechodzilem na C++ -- w nim wprowadzono przestrzen nazw std, dzieki czemu nigdy jej nieswiadomie nie naruszysz.

Chyba strcat() -- nie chce mi sie disasemblowac libc. :-)

Na moim instytutowym pececie, uzylem GCC 3.4 pod Windows XP.

Ponizej masz zasadnicza czesc, dopisanie reszty jest trywialne. Sam pomysl jest prosty, ale ze wzgledu na rozwleklosc C++ kod wyglada dosc groznie:

#include <limits.h>

template <bool> struct assert; template <> struct assert<true> {};

// Check whether the class T1 has the same type as the class T2

template <class T1, class T2> struct same { enum { is = false }; }; template <class T> struct same<T,T> { enum { is = true }; };

// Type selector

template <bool, typename T, typename F> struct select_type; template <typename T, typename F> struct select_type<true,T,F> { typedef T type; }; template <typename T, typename F> struct select_type<false,T,F> { typedef F type; };

namespace internal {

// Range boundary type selector

template <typename T> struct range_type; template <> struct range_type<signed> { typedef signed long long int type; }; template <> struct range_type<unsigned> { typedef unsigned long long int type; }; }

// Integer range type

template <typename T, typename internal::range_type<T>::type min_, typename internal::range_type<T>::type max_, bool check_ = false, bool strict_ = false> class range {

private:

// Check whether the specified range is valid

enum { _valid = sizeof(assert<(min_ <= max_)>) };

// Range internal type

typedef typename select_type<same<signed,T>::is, typename select_type<(((typename internal::range_type<signed>::type) min_) >= CHAR_MIN && ((typename internal::range_type<signed>::type) max_) <= CHAR_MAX) && strict_, signed char, typename select_type<(((typename internal::range_type<signed>::type) min_) >= SHRT_MIN && ((typename internal::range_type<signed>::type) max_) <= SHRT_MAX) && strict_, signed short int, typename select_type<(((typename internal::range_type<signed>::type) min_) >= INT_MIN && ((typename internal::range_type<signed>::type) max_) <= INT_MAX), signed int, typename select_type<(((typename internal::range_type<signed>::type) min_) >= LONG_MIN && ((typename internal::range_type<signed>::type) max_) <= LONG_MAX), signed long int, signed long long int >::type >::type >::type >::type, typename select_type<(((typename internal::range_type<unsigned>::type) max_) <= UCHAR_MAX) && strict_, unsigned char, typename select_type<(((typename internal::range_type<unsigned>::type) max_) <= USHRT_MAX) && strict_, unsigned short int, typename select_type<(((typename internal::range_type<unsigned>::type) max_) <= UINT_MAX), unsigned int, typename select_type<(((typename internal::range_type<unsigned>::type) max_) <= ULONG_MAX), unsigned long int, unsigned long long int >::type >::type >::type >::type >::type range_t;

range_t m_Value; // ta zmienna ma dokladnie tyle bajtow, ile potrzeba. :-)

Tu sie zaczynaja jakies operatory, konstruktory itd., nic ciekawego. Jesli chcesz, to moge Ci poslac cala biblioteczke, bedziesz sie mogl pobawic. :-)

Nie, jest dokladnie taki sam. Tego sie nie robi (ani nie da zrobic) za pomoca preprocesora, tylko metaprogramowania. Na przyklad znalezienie najwiekszego wspolnego dzielnika (wklejam programik studenta :-)):

#include <iostream>

//zaleznosc rekurencyjna dana jest wzorem: nwd(a,b)=nwd(b,a mod b)

template<unsigned int a, unsigned int b>struct GCD{ enum{val=GCD::val}; };

//specjalizacja - przypadek szczegolny: nwd(a,0)=a

template<unsigned int a>struct GCD{ enum{val=a}; };

int main(void){

std::cout<<GCD<12,45>::val<<std::endl; return 0; }

Masz, powiedzmy, wzorzec N-elementowego wektora liczb typu double. Chcemy dodac wektory A i B, zapisujac wynik w C, co mozna zapisac tak:

for(unsigned int i = 0; i < N; ++i) C[i] = A[i] + B[i];

N jest stala, ale rozwijanie petli w kompilatorach bywa takie sobie, wiec dobrze wymusic to w przenosny sposob. Jesli N=2, to kompilator ma automatycznie wygenerowac:

C[0] = A[0] + B[0]; C[1] = A[1] + B[1];

Jesli N=3, to:

C[0] = A[0] + B[0]; C[1] = A[1] + B[1]; C[2] = A[2] + B[2];

i tak dalej, a jak N jest duze, np >= 5, to kompilator ma nie rozwijac, lecz zostawic petle. No i jak to zrobic w C? :-)

Tej nie zuzywamy ani bitu.

Czyli w sumie tylko funkcje wirtualne i RTTI. No to po prostu tego nie uzywaj, to Ci sie nic nie dolaczy. :-)

"Przypadkiem"? :-)

dynamic_cast<>().

Mozliwe, ale po co uzywac dynamicznego sprawdzania typu? Przyznam szczerze, ze w zyciu jeszcze nie mialem takiej potrzeby.

Nie wiem, pewnie to zalezy od linkera. Na pewno wyrzuci funkcje nieuzywane w danej jednostce translacji, ale globalnej analizy przeplywu raczej nie przeprowadzi.

Pozdrawiam Piotr Wyderski

No dobra - jesli nie pisze specjalista to niech nie ma pretensji :-)

Jakos nikt tego problemu wczesniej nie zglaszal .. moze go nie bylo ? :-)

No fakt, mozliwe.

Pytanie o tyle istotne ze w wielu przypadkach x86 prosciej i lepiej wpisac kod wyliczajacy strlen niz ta funkcje wywolac :-)

[...]

No przekombinujesz :-)

Chyba RTTI mi chodzilo.

A do dyspozycji tylko 4KB :-)

J.

Sprawdzilem, jest bajtem, ale conieco dziwnie traktowanym.

Jasne. IMHO na podstawie pisania i ogladania kodu z GCC, wydaje mi sie ze najlepiej zadefiniowac zmienna w rejestrze, a odwolywac sie do niej bitowo. To dziala najlepiej bo w asmie tlumaczenie jest tak jak powinno, czyli np. za pomoca SBRS.

Tia, na podstawie 'Twojego' pdf-a juz troche wypalilem monitor ;-))

Rowniez... tygrysku ;-))))

[...]
[...]

No dobra... doigraliscie sie, od jutra wracam do asemblera... a wlasciwie to lepiej chyba bedzie jak wroce do uprawy marchewki...

A moze byl, ale o nim nie slyszales? :-) Przestrzeni nazw nie wprowadzono bez powodu.

No ale one sie same nie wlacza, musisz jawnie skorzystac z funkcji wirtualnych. Gdy sie zas pisze przed funkcja slowo kluczowe 'virtual', to trudno nazwac takie uzycie przypadkowym. :-)

Prawie wszystkie kompilatory pozwalaja to wylaczyc, bo jest bardzo rzadko uzyteczne. W GCC masz do tego opcje -fno-rtti i po problemie. :-)

Ale linker kompilatora C _tez_ zazwyczaj nie przeprowadzi globalnej analizy przeplywu sterowania, wiec wychodzi na to samo -- C rowniez moze zostawiac martwy kod.

Pozdrawiam Piotr Wyderski

Taaa... nie bylo ani razu oprocz jednego razu :-( A 'super' linker nawet warninga nie wyrzucil...

On Thu, 29 Apr 2004 09:47:28 +0200, jerry1111 <stop_this_spam_jerry1111 snipped-for-privacy@remove.wp.pl> wrote: [.....]

Czy masz na myśli jakiś super produkt IAR-a? ;-)

Regards, /J.D.

Jesli nalozyles na funkcje biblioteczna, to nie mial prawa. Biblioteki przeszukuje sie zeby znalezc niezdefiniowane symbole, a nie duplikaty :-)

J.

Hehehe :-) Akurat nie tym razem (az dziwne, prawda?). To byl siakis kompilator do PICa (afair do PIC17) - kilka lat temu. Pamietam, ze po jakiejs poprawce ten blad zniknal. Nie pamietam tylko jakiej firmy byl kompilator -

- bo i tak na koniec wyladowalem z MPLAB-C.

A czemu mial wyrzucic? Przeciez znalazl to, czego szukal. :o)))

Pozdrawiam Piotr Wyderski

Join the Discussion

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

Didn't find your answer?

Ask the community — no account required