7 WEJŚCIE I WYJŚCIE ____ ________
printf(s); /* ŹLE, jeśli w s występuje % */
printf(”%s”, s); /* BEZPIECZNIE */
Funkcja sprintf dokonuje tych samych przekształceń, co printf, ale wynik zapisuje w tablicy znakowej:
int sprintf(char *string, char *format, argl, arg2, ...)
Funkcja sprintf formatuje wartości argumentów argl, arg2 itd. na podstawie specyfikacji przekształceń podanych w argumencie format (według powyższego opisu). Jednak zamiast kierować wynik do wyjścia, umieszcza go w miejscu wskazanym argumentem string. Pamięć wskazywana przez string musi być wystarczająco obszerna, aby pomieścić cały wynikowy tekst.
Ćwiczenie 7.2. Napisz program, który w jakiejś sensownej formie wypisze dowolny strumień znaków wejściowych. Program powinien przynajmniej wypisywać znaki niegraficzne w postaci ósemkowej lub szesnastkowej (zależnie od miejscowych zwyczajów), a także dzielić zbyt długie wiersze.
Prezentujemy tutaj realizację minimalnej wersji funkcji printf, aby pokazać, jak napisać przenośnie funkcję posługującą się listą argumentów o zmiennej liczbie elementów. Głównie interesuje nas przetwarzanie argumentów, toteż nasza funkcja minprintf będzie sama opracowywała format i resztę argumentów, ale do wykonania przekształceń formatujących wywoła prawdziwą printf.
A oto właściwa deklaracja funkcji printf: int printf(char *fmt, ...)
w której deklaracja ... (trzy kropki) oznacza, że liczba i typy pozostałych argumentów nie są znane. Taka deklaracja może wystąpić jedynie na końcu listy argumentów. Zatem naszą funkcję minprintf deklarujemy następująco:
void minprintf(char *fmt, ...)
nie będziemy bowiem zwracać licznika znaków, tak jak to robi printf.
Sztuczka polega na tym, że minprintf maszeruje wzdłuż listy argumentów, choć tafli* ma nawet nazwy. Standardowy nagłówek <stdarg.h> zawiera zestaw makr, które finiują sposób poruszania się po takiej liście. Realizacje tego nagłówka będą różn‘L
7.3 ZMIENNA DŁUGOŚĆ LIST ARGUMENTÓW
powered by
Mi sio
się między sobą zależnie od maszyny, ale posługiwanie się nim jest dym środowisku C.
Zmienną odnoszącą się po kolei do każdego argumentu deklaruje się z typem va_list. W funkcji minprintf taka zmienna nazywa się ap, czyli wskaźnik do argumentów (od ang. argument pointer). Standardowe makro va_start inicjuje zmienną ap tak, aby wskazywała na pierwszy nienazwany argument. Ogólnie na liście argumentów musi wystąpić co najmniej jeden argument z nazwą; makro va_start, aby rozpocząć działalne, potrzebuje ostatniego nazwanego argumentu.
Każde wywołanie makra va_arg udostępnia jeden argument i przesuwa ap do następnego; do określenia typu szukanej wartości i rozmiaru kroku, o jaki trzeba przesunąć ap, makro va_arg potrzebuje nazwy typu. Ostatnie makro va_end czyści wszystko, co wymaga czyszczenia; va_end musi być wywołane przed zakończeniem działania funkcji.
Te właściwości tworzą podstawę działania naszej uproszczonej wersji printf:
#include <stdarg.h>
#include <stdio.h>
I* minprintf: minimalna printf ze zmienną listą argumentów */ void minprintf(char *fmt, ...)
va Jist ap; /* wskazuje po kolei każdy nienazwany argument */ char *p, *sval; int ival; double dval;
va_start(ap, fmt); /* ap wskazuje 1. nienazwany argument */ for (p = fmt; *p; p++) { if (*p != '%’) { putchar(*p); continue;
switch (*++p) { case 'd ’:
ival = va_arg(ap, int); printf(”%d”, ival); break; case ’f’:
dval = va_arg(ap, double); printf(”%f', dval); break;
209
Język ANSI C