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
Format | Działanie |
---|---|
%% | Znak ASCII: % |
s | Ciąg znaków ASCII. |
c | Pojedynczy znak kodu ASCII. |
d | Liczba dziesiętna całkowita ze znakiem. |
i | Liczba dziesiętna całkowita ze znakiem. |
e | Liczba dziesiętna w zapisie naukowym (mała litera e). |
E | Liczba dziesiętna w zapisie naukowym (duża litera E). |
f | Liczba dziesiętna zmiennoprzecinkowa (wraca małe litery w przypadku, gdy wynik jest:: inf, infinity, lub nan). |
F | Liczba dziesiętna zmiennoprzecinkowa (zwraca duże litery w przypadku, gdy wynik jest:: INF, INFINITY, lub NAN). |
g | Wybiera format e lub f w zależności, który będzie krótszy (mniej znaków). |
G | Wybiera format E lub F w zależności, który będzie krótszy (mniej znaków). |
o | Liczba ósemkowa całkowita bez znaku. |
u | Liczba dziesiętna bez znaku. |
x | Liczba szesnastkowa bez znaku (małe litery). |
X | Liczba szesnastkowa bez znaku (duże litery). |
p | Wskaź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ów | działanie |
---|---|
d, i, o, u, x, X | minimalna liczba cyfr, które mają być wyświetlone (domyślnie 1) |
a, A, e, E, f, F | liczba cyfr, które mają być wyświetlone po kropce (domyślnie 6) |
g, G | liczba cyfr znaczących (domyślnie 1) |
s | maksymalna 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:
Flaga | działanie |
---|---|
- (minus) | wymuszaj wyrównanie do lewej |
+ (plus) | liczby zawsze mają być poprzedzone znakiem (+ lub -) |
spacja | liczby 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
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?
OdpowiedzUsuńChyba jestem zbyt ograniczony (żeby nie napisać zbyt głupi) by zrozumieć C dla mikrokontrolerów.
Makabra.
I znowu nastawiłeś się negatywnie :-)
OdpowiedzUsuń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 :-)
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ń.
OdpowiedzUsuń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.
No widzisz, czyli zasady są takie same, tylko:
OdpowiedzUsuń- 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.
A będzie jakaś rozpiska czym się różnią funkcje: printf, fprintf, sprintf, snprintf, vprintf, vfprintf, vsprintf oraz vsnprintf? :)
OdpowiedzUsuńJęzyk C Prata lub Kochan i wszystko się wyjaśni
OdpowiedzUsuń