logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[AVR][C] - typy zmiennych - pytanko

mirekk36 29 Paź 2008 16:09 6213 10
  • #1 5680012
    mirekk36
    Poziom 42  
    Witam,

    ja znowu w temacie C ;)

    .... jak to jest z tymi typami zmiennych tak na prawdę?

    np czym się różni unsigned char od uint8_t ??? chyba niczym? dobrze myślę?

    teoretycznie z tego co już wiem to typ char jest liczbą z zakresu -128 do 127 więc czemu funkcja itoa (poniżej w kodzie funkcja lcd_dec jak podam jej liczbę np 250 lub znak o kodzie 250 to wyświetla mi na lcd 250 a nie jakąś ujemną liczbę?

    void lcd(char* str)
    {
    	char znak;
    	while ( 0 != (znak = *(str++)) )
    		lcd_send(_DATA, ( (znak>=0x80) && (znak<=0x87) ) ? (znak & 0x7F) : znak);
    }
    
    // funkcja wyświetla liczby dziesiętne na wyświetlaczu LCD
    void lcd_dec(int val)
    {
    	char bufor[7];
    	lcd( itoa(val, bufor, 10) );
    }


    wiem , że gdzieś w swojej dotychczasowej wiedzy czy przemyśleniach popełniam chyba jakiś błąd. Ale wprowadzają u mnie zamieszanie różnorakie kody napisane w C, które przeglądam gdzie:

    - po piwerwsze nie wiedzieć czemu ludzie często korzystają z typedef i np robią coś takiego:

    typedef unsigned char u8;

    albo

    typedef char s8;

    czy to tylko po to żeby krócej pisać? czy są jakieś inne cele które przyświecają takim różnym podmianom typów we własnych programach.

    jakieś może wskazówki ogólne - czego się trzymać korzystając z pewnych typów?
  • Pomocny post
    #2 5680061
    szelus
    Poziom 34  
    W skrócie. Nie jest nigdzie powiedziane, że typ char ma 8 bitów. O ile pamiętam, jest tylko zagwarantowane, że zajmuje nie więcej bitów, niż int.
    Dlatego wprowadzono (standard C99) typy uint8_t, int8_t, int32_t itd. aby zagwarantować, że na wszystkich platformach te typy mają ściśle określoną reprezentację.
    Przed C99, z powyższego powodu definiowano zwykle przez typedef własne typy o ściśle zdefiniowanych długościach, aby uprościć przenoszenie kodu pomiedzy różnymi platformami i zwiększyć czytelność. Ale z braku standardu zrobił się też lekki bałagan ;)

    Żeby było trudniej, czasami kompilatory mają opcje pozwalające na np. wymuszenie typu char jako unsigned, np avr-gcc taką ma. Upewnij się, że nie jest u Ciebie włączona w makefile (coś jak -funsigned-char, czy coś w ten deseń).

    P.S. Jak podajesz znak o kodzie 250? W ten sposób?
    
        lcd_dec(`\0372`);
    

    Czy jakoś podobnie? Bo u Ciebie funkcja lcd_dec() przyjmuje argument typu int, więc jak podasz liczbe 250, to masz 250. Chyba, że:
    
        lcd_dec( (char)250 );
    

    W jednym i drugim przypadku wychodziłoby, że masz char jako unsigned.
  • #3 5680180
    mirekk36
    Poziom 42  
    no troszkę mi się rozjaśniło, opcję -funsigned-char AVR Studio ma ciągle włączoną i nie można jej wyłączyć.

    więc jeśli GCC wymusza mi dla typu char typ unsigned char to już jakby dociera do mnie dlaczego tak a nie inaczej zachowuje mi się kodzik
  • #4 5680291
    szelus
    Poziom 34  
    Czy w AVR Studio można to wyłączyć, to nie mam pojęcia, bo ciągle jeszcze nie zainstalowałem ;)
    Dla avr-gcc akurat ta opcja, chociaż powoduje zachowanie niezgodne ze standardem, jest uzasadniona. Konwersja z unsigned jest na AVR prostsza, więc dostajemy krótszy kod. Z drugiej strony, o znakach nikt nie myśli, że mogą mieć ujemne kody, więc pod tym względem standard jest trochę bez sensu. ;) A jeżeli komuś b. zależy (znaczy pasuje mu zakres -128..+127), to zawsze ma int8_t do dyspozycji. Mamy juz rok 2008 i najlepiej odzwyczaić się od myślenia, że do reprezantacji 8 bitów służy typ char.
  • #5 5680453
    skynet_2
    Poziom 26  
    mirekk36 napisał:
    no troszkę mi się rozjaśniło, opcję -funsigned-char AVR Studio ma ciągle włączoną i nie można jej wyłączyć.


    dlaczego nie można ? odznaczasz, zapisujesz projekt i restartujesz AVR studio i masz odznaczoną wiec co ci nie działa ?

    Ja mam problem bo mi nie otwiera poprzedniego projektu po włączeniu i musze go ręcznie otworzyć co strasznie wnerwia.
  • #6 5682285
    Dr.Vee
    VIP Zasłużony dla elektroda
    Standard mowi też, że char, signed char i unsigned char to trzy różne typy. Jeśli kompilujesz z opcją -Wconversion to dostaniesz warningi przy domyślnych konwersjach pomiędzy typami, które nie są kompatybilne co do znaku. Tych warningów będzie dość dużo ;)

    Pozdrawiam,
    Dr.Vee
  • #7 5682445
    mirekk36
    Poziom 42  
    Dr.Vee -> no właśnie poruszyłeś dla mnie ciekwy wątek, bo np taka osoba jak ja, początkujaca w C - nie mam zbytniego pojęcia o tym aby cokolwiek "ręcznie" ustawiać w makefile po pierwsze. Po drugie takie progrmay jak AVR Studio potrafią same generować ten plik na podstawie różnych ustawień a np Eclipse - w ogóle nie zaleca "ręcznej" konfiguracji i zmiany generowanego przez niego makefile.

    więc moje pytanie dotyczy tego np parametru o którym napisałeś -Wconversion, on u mnie się w ogóle nie pojawia w makefile a pomimo to mam warningi przy takich ustawieniach jak poniżej na obrazku:
    [AVR][C] - typy zmiennych - pytanko

    o takie warningi:
    ../lcd.c:342: warning: pointer targets in passing argument 1 of 'lcd' differ in signedness
    
    ../lcd.c:342: warning: pointer targets in passing argument 2 of 'itoa' differ in signedness


    a funkcja wygląda tak:
    // funkcja wyświetla liczby dziesiętne na wyświetlaczu LCD
    void lcd_dec(int val)
    {
    	unsigned char bufor[7];
    	lcd( itoa(val, bufor, 10) );
    }


    oczywiście gdy wyłączę te ptaszki zaznaczone na czerwono to warningi znikają.

    Zastanawiam się więc kiedy tzn w jakich sytuacjach trzeba na nie zwracać uwagę a kiedy nie ?

    teoretycznie wiadomo, że warningi można sobie odpuścić i się nimi nie przejmować bo się skompilowało i już. Jednak z tego co widzę dotychczas takie podejście może być jednak zabójcze i powodować często wielogodzinne później szuganie "buga" w kodzie
  • Pomocny post
    #8 5682642
    Dr.Vee
    VIP Zasłużony dla elektroda
    mirekk36 napisał:
    więc moje pytanie dotyczy tego np parametru o którym napisałeś -Wconversion, on u mnie się w ogóle nie pojawia w makefile a pomimo to mam warningi przy takich ustawieniach jak poniżej na obrazku:
    ...

    Prototypy Twoich funkcji to:
    void lcd(char *);
    char* itoa(int, char*, int);

    Jak już pisałem - char, signed char i unsigned char to są trzy różne typy - i nie ma znaczenia, czy "goły" char jest ze znakiem czy bez - po prostu typy są różne i nie możesz jednym zastąpić drugiego (bez rzutowania, albo bez warninga).

    Co do Twoich opcji -f, to tylko pierwsza ma tutaj znaczenie:

    -funsigned-char wyjaśnił już kolega powyżej; dzięki tej opcji gcc generuje mniejszy kod, bo funkcje zwracajace char domyślnie maja wartość zwracaną rozszerzaną do int - czyli przy signed char trzeba rozszerzyć znak, a przy unsigned nie trzeba = prostszy kod.

    -funsigned-bitfields prawdopodobnie nigdy nie będziesz używał "pól bitowych", bo nikt ich nie używa :) Chodzi o "upychanie" zmiennych w strukturze przez podanie ilości bitów, jakie się rezerwuje dla danego pola:
    tstruct test {
       int pole_3_bitowe:3;
       int pole_5_bitowe:5;
    };

    -fpack-struct włącza "upychanie" elementów struktur tak, że nie ma między nimi pustych miejsc (domyślnie kompilator zostawia puste miejsca na "wyrównanie" adresów dla optymalnego dostępu do pamięci - na AVR bez znaczenia).

    -fshort-enums typy "wyliczeniowe" domyślnie mają szerokość int-a, bez znaczenia ile jest elementów do wyliczenia. Ta opcja włącza dostosowanie szerokości zmiennych enum do maks. ilości elementów wyliczenia - kod skompilowany z tą opcją nie jest kompatybilny z kodem kompilowanym bez tej opcji.

    Jak coś, to więcej informacji na cały-czas-polecanych-przeze-mnie stronach avr-libc.

    Pozdrawiam,
    Dr.Vee
  • #9 5705434
    Dave_Masters
    Poziom 14  
    Dr.Vee napisał:

    -funsigned-bitfields prawdopodobnie nigdy nie będziesz używał "pól bitowych", bo nikt ich nie używa :)


    Masz racje, że prawdopodobnie ich nie użyje, ale nie pisz, że nikt tego nie robi. AVR nie poraża ilością pamięci i takie pakowanie danych pozwala uzyskać naprawdę spore oszczędności miejsca.
    W moim przypadku udało się zaoszczędzić 50% miejsca (3B na każdy element tablicy). Nie zmienia to jednak faktu, że z kilkoma zmiennymi które "są luzem", a nie w tablicy nie ma co się bawić w pakowanie :)
  • #10 5705763
    Dr.Vee
    VIP Zasłużony dla elektroda
    "Pola bitowe" są praktycznie nieużywane, bo standard C nie specyfikuje w jaki sposób poszczególne pola są rozmieszczone w pamięci. Taki sam efekt można osiągnąć używając masek i przesunięć bitowych, wtedy przynajmniej wiadomo który bit jest gdzie (ważne np. przy dostępie do rejestrów sprzętowych).

    Pozdrawiam,
    Dr.Vee
  • #11 5705785
    Dave_Masters
    Poziom 14  
    Tak też pierwotnie zrobiłem. Jednakże w projekcie nie było istotne gdzie znajdowały się konkretne pola bitowe, a na ich korzyść przemówiła wygoda odwołań. Próbowałem to robić makrami, ale przyzwyczajenia z programowania obiektowego robią swoje (jednak ta kropka fajnie wygląda :P )
REKLAMA