Mikrokontrolery - Jak zacząć?

... czyli zbiór praktycznej wiedzy dot. mikrokontrolerów.

czwartek, 10 lutego 2011

Kurs języka C: Printf() i funkcje pochodne


Autor: Dondu

Kurs języka C: Spis treści


Funkcje z rodziny printf, formatują tekst podany w argumentach w sposób określony jednym lub wieloma formatami. Tekst ten powstaje z ciągów znaków ASCII oraz liczb dowolnych typów.

Do rodziny tej należą funkcje: printf, fprintf, sprintf, snprintf, vprintf, vfprintf, vsprintf oraz vsnprintf.

Argumenty funkcji wpisuje się według szablonu:

%[flaga][szerokość][.precyzja][format]

Nawiasy kwadratowe oznaczają, iż dany parametr jest opcjonalny, czyli może lecz nie musi występować.




[format]

Ciągi znaków powstające z liczb i znaków ASCII możesz formatować za pomocą dostępnych opcji formatu:

Tabela 1 - Dostępne formaty i ich działanie

FormatDziałanie
%%Znak ASCII: %
sCiąg znaków ASCII.
cPojedynczy znak kodu ASCII.
dLiczba dziesiętna całkowita ze znakiem.
iLiczba dziesiętna całkowita ze znakiem.
eLiczba dziesiętna w zapisie naukowym (mała litera e).
ELiczba dziesiętna w zapisie naukowym (duża litera E).
fLiczba dziesiętna zmiennoprzecinkowa (wraca małe litery w przypadku, gdy wynik jest:: inf, infinity, lub nan).
FLiczba dziesiętna zmiennoprzecinkowa (zwraca duże litery w przypadku, gdy wynik jest:: INF, INFINITY, lub NAN).
gWybiera format e lub f w zależności, który będzie krótszy (mniej znaków).
GWybiera format E lub F w zależności, który będzie krótszy (mniej znaków).
oLiczba ósemkowa całkowita bez znaku.
uLiczba dziesiętna bez znaku.
xLiczba szesnastkowa bez znaku (małe litery).
XLiczba szesnastkowa bez znaku (duże litery).
pWskaźnik.


W kompilatorze CManiak znajdziesz przygotowany przykład nr 1 pokazujący wynik pracy funkcji printf() dla poszczególnych formatów. Porównaj otrzymane wyniki z odpowiadającymi im liniami kodu w kompilatorze:

Przykład 1 (w kompilatorze)
  printf("Znak ASCII: %%");
  printf("Ciąg znaków ASCII: %s",  "jakis tekst");
  printf("Znak ASCII o kodzie 65: %c",  65);
  printf("Liczba dziesiętna całkowita ze znakiem: %d",  -65);
  printf("Liczba dziesiętna całkowita ze znakiem: %i",  -65);
  printf("Liczba dziesiętna w zapisie naukowym (małe e): %e", -165.1235);
  printf("Liczba dziesiętna w zapisie naukowym (duże E): %E", -165.1235);
  printf("Liczba dziesiętna zmiennoprzecinkowa: %f",  -165.1235);
  printf("Liczba dziesiętna zmiennoprzecinkowa: %F",  -165.1235);
  printf("W zależności co krótsze %%e czy %%f : %g",  12213365.133235);
  printf("W zależności co krótsze %%e czy %%f : %g",  12215.133);
  printf("W zależności co krótsze %%E czy %%F : %G",  12213365.133235);
  printf("W zależności co krótsze %%E czy %%F : %G",  12215.133);
  printf("Liczba ósemkowa całkowita bez znaku: %o",  64);
  printf("Liczba dziesiętna całkowita bez znaku: %u",  65);
  printf("Liczba szesnastkowa bez znaku (małe litery) %x",  346874);
  printf("Liczba szesnastkowa bez znaku (duże litery) %X",  346874);
  
  int a=1234;    //deklaracja zmiennej o wartości 1234
  printf("Wskaźnik (adres zmiennej a): %p", &a); //pokaż wskaźnik



[szerokość]

Za pomocą tego parametru ustala się jaką szerokość liczoną w ilości znaków ASCII ma mieć wynik działania funkcji.

Jeżeli wynik ma mniej znaków niż określa to parametr [szerokość], to wyrównywany jest przez dodanie spacji z lewej strony. Innymi słowy możesz w ten sposób wyrównywać liczby do prawej strony.

Na przykład jeżeli chcesz wyświetlić liczbę za pomocą formatu d o szerokości pola wynoszącej 6 cyfr, możesz zrobić tak:
%6d

Podobnie jest w przypadku ciągów znaków ASCII. Ponieważ do ciągów znaków stosujemy wg powyższej tabeli format s, stąd dla szerokości pola o 6 znakach, parametr ten zapiszemy podobnie jak w przypadku liczb:
%6s

Zobacz w kompilatorze CManiak jaki efekt otrzymasz uruchamiając przykład nr 2:

Przykład 2 (w kompilatorze)
  printf("%6d", 1235);
  printf("%6d", 78);
  printf("%6d", 6);
  printf("%6d", 455897);

  char tekst[]="abcd";   //ciąg znaków w zmiennej tekst
  printf("%6s", tekst);




[.precyzja]

Parametr ten pozwala ustalić jaką precyzję czyli ilość cyfr, które mają zostać pokazane. Liczba określająca precyzję musi być poprzedzona kropką.

Precyzja dla poszczególnych formatów ma różne znaczenie:

Tabela 2 - Parametr precyzji dla poszczególnych formatów:

dla formatówdziałanie
d, i, o, u, x, Xminimalna liczba cyfr, które mają być wyświetlone (domyślnie 1)
a, A, e, E, f, Fliczba cyfr, które mają być wyświetlone po kropce (domyślnie 6)
g, Gliczba cyfr znaczących (domyślnie 1)
smaksymalna liczba znaków


Poniższy przykład pokazuje po jednym przypadku z tabeli 2. Zobacz jak wykona przykład nr 3 kompilator CManiak.

Przykład 3 (w kompilatorze)
  printf("%.3d", 5);  
  printf("%.3f", 5397.9876); 
  printf("%.3g", 5397.9876); 
  printf("%.3s", "CManiak jest super!"); 




[szerokość.precyzja]

Teraz połączmy parametr szerokości i precyzji. Otrzymamy w ten sposób liczby i teksty o odpowiedniej precyzji wyrównane do prawej.

Zobacz efekt uruchomienia kodu przykładu 4 w kompilatorze CManiak.

Przykład 4 (w kompilatorze)
  printf("%12.3d", 5);  
  printf("%12.3f", 5397.9876); 
  printf("%12.3g", 5397.9876); 
  printf("%12.3s", "CManiak jest super!"); 




[flaga]

Parametr flaga może dodatkowo modyfikować znaczenie pozostałych parametrów.
Uwaga! Flaga ma nadrzędne znaczenie przez co czasami zmienia działanie innych parametrów.

Tabela 3 - Flagi i ich znaczenie:

Flagadziałanie
- (minus)wymuszaj wyrównanie do lewej
+ (plus)liczby zawsze mają być poprzedzone znakiem (+ lub -)
spacjaliczby nieujemne mają być poprzedzone spacją
# (hash)dla formatu o (liczba ósemkowa) wymusza zero na początku.
dla formatów x lub X (liczba szesnastkowa) wymusza dodanie na początku
odpowiednio 0x lub 0X
dla formatów a, A, e, E, f, F, g, G wymusza kropkę nawet wtedy,
gdy nie ma żadnych cyfr części ułamkowej.
dla formatów g lub G końcowe zera nie są usuwane
0 (zero)Dla formatów: d, i, o, u, x, X, a, A, e, E, f, F, g, G
wymusza uzupełnienie wyrównania zerami zamiast spacjami.
Dla formatów: d, i, o, u, x, X jeżeli określona jest precyzja, to flaga ta jest ignorowana.

Poniżej przykłady użycia flag.


Flaga: - (minus)

Przykład oprzemy o pole szerokości 12 znaków, precyzji 3 znaków dla liczby całkowitej dziesiętnej równej 5. Uruchamiając przykład w kompilatorze CManiak zobaczysz jak realizowane jest wymuszenie flagą - (minus) wyrównania do lewej pomimo, że określamy szerokość pola na 12 znaków, co powinno było wyrównać liczbę do prawej.

Przykład 5 (w kompilatorze)
  printf("%-12.3d\n", 5);  
  printf("%12.3d", 5);  



Flaga: + (plus)

Prosty przykład dla liczb całkowitych dziesiętnych dodatniej i ujemnej z użyciem flagi + (plus). Znak zawsze jest dodawany, niezależnie, czy jest on plusem,, czy minusem. Sprawdź uruchamiając przykład w kompilatorze CManiak.

Przykład 6 (w kompilatorze)
  printf("%+d", 0); 
  printf("%+d", 5317); 
  printf("%+d", -5317); 



Flaga: spacja


Poniżej przykład dla liczb całkowitych dziesiętnych dodatniej i ujemnej z użyciem flagi + (plus). Dla liczb nieujemnych dodana zostanie spacja z przodu. Sprawdź uruchamiając przykład w kompilatorze CManiak.

Przykład 7 (w kompilatorze)
  printf("% d", 0); 
  printf("% d", 5317); 
  printf("% d", -5317); 



Flaga: 0 (zero)


Przykład pokazuje użycie flagi 0 (zero) dla liczby całkowitej dziesiętnej przy żądaniu, by pole miało szerokości 12 znaków. Rezultat możesz sprawdzić uruchamiając ten przykład w kompilatorze CManiak.

Przykład 8 (w kompilatorze)
  printf("%012d", 0); 
  printf("%012d", 5317); 
  printf("%012d", -5317); 




Flaga: # dla formatu o


Format o dotyczy liczb ósemkowych. Przygotowałem przykład dla liczby ósemkowej 100 z użyciem flagi # (hash) oraz bez niej. W kompilatorze CManiak zobaczysz jak dodawane jest zero na początku liczby.

Przykład 9 (w kompilatorze)
  printf("%#o", 64);   //64 dziesiętnie to w kodzie ósemkowym 100
  printf("%o", 64);




Flaga: # dla formatów: x, X


Formaty x oraz X dotyczą liczb szesnastkowych. Zobacz więc jak flaga # w połączeniu z tymi formatami powoduje dodanie na początku liczby przedrostków odpowiednio 0x lub 0X. W CManiak'u także dostępny jest ten przykład.


Przykład 10 (w kompilatorze)
  printf("%#x", 32498); //32498 dziesiętnie, to w kodzie szesnastkowym 7ef2
  printf("%x", 32498);



Flaga: # dla formatów: 
a, A, e, E, f, F, g, G

Dla tych formatów (liczby zmiennoprzecinkowe) flaga # wymusza kropkę nawet wtedy, gdy nie ma żadnych cyfr części ułamkowej. I znowu CManiak zaprezentuje Ci działanie tej flagi.


Przykład 11 (w kompilatorze)
  printf("%#12.0f", 789.0);
  printf("%12.0f", 789.0);




Flaga: # dla formatów: 
g, G

Dla tych formatów flaga # wymusza pozostawienie końcowych zer. CManiak czeka gotowy do pracy :-)


Przykład 12 (w kompilatorze)
  printf("%#g", 789.0);
  printf("%g", 789.0);


Kurs języka C: Spis treści

29
Oceń artykuł.
Wasze opinie są dla nas ważne, gdyż pozwalają dopracować poszczególne artykuły.
Pozdrawiamy, Autorzy
Ten artykuł oceniam na:

5 komentarzy:

  1. Nie no bez kitu, kompletnie tego nie rozumiem. Przykład pierwszy, po co te wszystkie literki ze znakami % skoro i tak na kocu po kompilacji otrzymujemy praktycznie to samo?

    Chyba jestem zbyt ograniczony (żeby nie napisać zbyt głupi) by zrozumieć C dla mikrokontrolerów.

    Makabra.

    OdpowiedzUsuń
  2. I znowu nastawiłeś się negatywnie :-)

    Ponieważ jesteś użytkownikiem BASCOM'a, to pokażę Ci na przykładzie.

    W BASCOM, by przygotować ciąg znaków (dla instrukcji LCD) zamieniając z liczby zmiennoprzecinkowej, trzeba użyć dwóch funkcji:
    - str()
    - Format()

    na przykład w taki sposób:

    LCD Format(str(temper) , "0.0") ; "C"

    Gdy zmierzona temperatura w zmiennej temper wynosi 12.598 w wyniku działania powyższego kodu BASCOM otrzymasz ciąg znaków: 12.6C

    Odpowiednikiem tego w języku C jest:

    printf("%.1fC", temper);

    gdzie:
    %.1f - poznasz z przykładu nr 1 i 3 i ich opisów,
    C - to tylko literka do wyświetlenia na końcu

    W rezultacie otrzymamy także: 12.6C

    Dołączam kompletny kod:
    #include
    int main(void){
    float temper = 12.598;
    printf("%.1fC", temper);
    return 0;
    }

    PS.
    Więcej optymizmu :-)

    OdpowiedzUsuń
  3. Staram się być optymistyczny i to jak nigdy dotąd, ale to nie jest proste. Myślę że najprościej było by mi zrozumieć właśnie na zasadzie porównań.

    Poza tym nie trzeba używać dwóch funkcji, starczy jedna. Ja używałem formatowania Fusing bo jest prostsze:

    temper=fusing(zmienna,x.xx)

    temper - nowy wynik jaki otrzymamy
    zmienna - liczba poddawana konwersji
    x.xx - format jaki otrzymamy

    Nie pomyśl że to znowu złe nastawienie do C, ale chciałem pokazać że bascom tez potrzebuje tylko jednej linii żeby uzyskać to samo.

    Tylko inną sprawą jest że bascom zamieni to pewnie na wiele linii asm.

    OdpowiedzUsuń
  4. No widzisz, czyli zasady są takie same, tylko:
    - zapis nieco inny,
    - printf ma prawdopodobnie (bo nie znam BASCOM) o wiele większe możliwości.

    Tak, wynikowy kod C będzie krótszy niż BASCOM. To jest między innymi związane z tym, że dokładnie informujesz kompilator czego oczekujesz: jakiego typu jest dana i jak ma z nią postępować. To pozwala mu na wybranie najkrótszego kodu wynikowego. To oczywiste, że kod wyspecjalizowany, będzie krótszy niż uniwersalny.

    BTW. Dobrze, że skomentowałeś artykuł, bo zauważyłem, że go jeszcze nie dokończyłem. Brakuje jeszcze modyfikatorów rozmiaru - dodam dzisiaj wieczorem.

    OdpowiedzUsuń
  5. A będzie jakaś rozpiska czym się różnią funkcje: printf, fprintf, sprintf, snprintf, vprintf, vfprintf, vsprintf oraz vsnprintf? :)

    OdpowiedzUsuń

Działy
Działy dodatkowe
Inne
O blogu




Dzisiaj
--> za darmo!!! <--
1. USBasp
2. microBOARD M8


Napisz artykuł
--> i wygraj nagrodę. <--


Co nowego na blogu?
Śledź naszego Facebook-a



Co nowego na blogu?
Śledź nas na Google+

/* 20140911 Wyłączona prawa kolumna */
  • 00

    dni

  • 00

    godzin

  • :
  • 00

    minut

  • :
  • 00

    sekund

Nie czekaj do ostatniego dnia!
Jakość opisu projektu także jest istotna (pkt 9.2 regulaminu).

Sponsorzy:

Zapamiętaj ten artykuł w moim prywatnym spisie treści.