Menu

Biblioteka standardowa C: mapa nagłówków, które warto znać

Co daje każdy nagłówek standardowy: stdio.h, stdlib.h, string.h, math.h, time.h, ctype.h, limits.h, stdbool.h, stdint.h i assert.h, z krótkim działającym przykładem dla każdego.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Sam język C jest malutki: typy, operatory, sterowanie przepływem, funkcje, wskaźniki. Nie potrafi niczego wypisać, przeczytać pliku, porównać napisów ani zaalokować pamięci. Wszystko to zapewnia biblioteka standardowa: zestaw nagłówków dostarczany przez każdą zgodną ze standardem implementację.

Ta strona to mapa. Każda sekcja mówi, do czego służy nagłówek, pokazuje jeden krótki działający przykład i odsyła do pełniejszej strony, jeśli taka istnieje.

stdio.h: wejście i wyjście

Nagłówek, który dołączasz jako pierwszy niemal w każdym programie. Zawiera printf i scanf, typ FILE i funkcje plikowe oraz bezpieczniejsze funkcje wczytujące całe linie.

Podstawy: printf, fprintf, sprintf, snprintf do wypisywania; scanf, fscanf, sscanf, fgets, getchar do wczytywania; fopen, fclose, fread, fwrite, fseek do plików. Dokładniej omawiają je strony printf, scanf i obsługa plików.

Jedna zasada warta zapamiętania: nigdy nie używaj gets(). Ta funkcja nie ma jak poznać rozmiaru bufora i została usunięta ze standardu w C11. Zamiennikiem jest fgets(buf, sizeof buf, stdin).

stdlib.h: narzędzia ogólne

Worek na wszystko: pamięć, konwersje, losowość, sterowanie procesem, sortowanie.

Najważniejsze: malloc, calloc, realloc, free (zobacz pamięć dynamiczna); atoi, atof, strtol, strtod do konwersji, przy czym lepsza jest rodzina strto*, która potrafi zgłosić błąd, podczas gdy atoi po cichu zwraca 0; rand i srand (zobacz liczby losowe); exit, abort, getenv, system; oraz qsort/bsearch.

string.h: napisy i bloki pamięci

Napisy w C to tablice char zakończone '\0', a każda operacja na nich to wywołanie funkcji.

Dwa nawyki chronią przed tym, by ten nagłówek stał się źródłem przepełnień bufora: zawsze znaj rozmiar miejsca docelowego i pamiętaj, że strcmp zwraca 0 dla równych napisów, więc if (strcmp(a, b)) jest prawdziwe, gdy napisy się różnią. Strona funkcje napisowe szczegółowo omawia bezpieczniejsze wzorce z strncpy/snprintf.

math.h: matematyka

sqrt, pow, fabs, floor, ceil, round, fmod, rodziny funkcji trygonometrycznych i logarytmów, INFINITY i NAN.

To jedyny nagłówek, który może wymagać flagi linkera: na Linuksie dodaj -lm na końcu polecenia kompilacji, inaczej linker zgłosi „undefined reference to sqrt”. Pełny przegląd na stronie funkcje matematyczne.

time.h: zegary i daty

Dwa przesunięcia w struct tm łapią każdego: tm_year liczy się od 1900, a tm_mon jest numerowane od 0. time(NULL) to też zwyczajowe ziarno dla srand.

ctype.h: klasyfikacja znaków

Mały nagłówek, ale bardziej przydatny, niż się wydaje. Każda funkcja przyjmuje znak i odpowiada na pytanie tak/nie albo zmienia wielkość liter.

Pełny zestaw: isalpha, isdigit, isalnum, isspace, isupper, islower, ispunct, isxdigit, isprint, a do tego toupper i tolower.

Zwróć uwagę na rzutowanie (unsigned char). Te funkcje są zdefiniowane dla wartości, które da się przedstawić jako unsigned char, oraz dla EOF. Zwykły char jest na większości systemów typem ze znakiem, więc bajt powyżej 127 przychodzi jako liczba ujemna, a wywołanie staje się niezdefiniowanym zachowaniem. Rzutowanie nic nie kosztuje i usuwa całą klasę problemów.

I wybieraj te funkcje zamiast ręcznych testów. c >= '0' && c <= '9' akurat działa, ale isdigit(c) mówi, o co ci chodzi, i pozostaje poprawne wszędzie.

limits.h i float.h: granice typów

Jak duży może być int na tej maszynie? Te nagłówki na to odpowiadają, a odpowiedzi pokazują, dlaczego przenośny kod pyta, zamiast zakładać.

INT_MAX pozwala sprawdzić przepełnienie zanim nastąpi, a to ważne, bo przepełnienie liczby ze znakiem to niezdefiniowane zachowanie, a nie zawinięcie wartości, które można sprawdzić po fakcie.

stdbool.h i stdint.h: lepsze typy

C nie miało typu logicznego aż do C99. Dostarcza go <stdbool.h>:

bool, true i false to makra dla _Bool, 1 i 0, ale sprawiają, że intencja jest oczywista. (W C23 stały się słowami kluczowymi i nagłówek nie jest już wymagany.)

<stdint.h> daje typy o gwarantowanej szerokości, niezbędne w formatach plików, protokołach sieciowych i wszystkim, co wbudowane, gdzie „int ma pewnie 32 bity” to za mało:

Makra w stylu PRId32 z <inttypes.h> rozwijają się do właściwego specyfikatora printf dla każdego typu o stałej szerokości na danej platformie. To przenośny sposób ich wypisywania, bo %d jest poprawne dla int32_t na niektórych systemach, a na innych nie.

assert.h: sprawdzanie założeń

assert(expr) nic nie robi, gdy wyrażenie jest prawdziwe, i przerywa program z komunikatem, gdy jest fałszywe.

Kompilacja z -DNDEBUG usuwa wszystkie asercje, więc w wersji produkcyjnej nic nie kosztują. To jest też ostrzeżenie: nigdy nie umieszczaj efektu ubocznego wewnątrz assert. assert(read_next() > 0) w wersji produkcyjnej całkowicie przestaje czytać, a wynikający z tego błąd pojawia się tylko na produkcji.

Asercje są na twoje błędy, czyli warunki, które przy poprawnym kodzie powinny być niemożliwe. Złe dane od użytkownika to nie asercja, tylko if i komunikat o błędzie.

Reszta w skrócie

  • <stddef.h>: size_t, ptrdiff_t, NULL, offsetof
  • <stdarg.h>: funkcje o zmiennej liczbie argumentów, mechanizm stojący za printf
  • <errno.h>: errno oraz perror i strerror do zgłaszania, dlaczego wywołanie się nie powiodło
  • <signal.h>: obsługa sygnałów, takich jak Ctrl-C
  • <setjmp.h>: skoki nielokalne, rzadko właściwa odpowiedź
  • <locale.h>, <wchar.h>, <wctype.h>: ustawienia regionalne i szerokie znaki
  • <stdnoreturn.h>, <stdalign.h>, <threads.h>, <stdatomic.h>: dodatki z C11

Dwa nawyki sprawiają, że z biblioteki korzysta się przyjemnie. Przeczytaj stronę podręcznika, zanim zaczniesz zgadywać sygnaturę: man 3 strtol na macOS i Linuksie jest źródłem autorytatywnym i szybkim. I sprawdzaj wartości zwracane: malloc, fopen i strtol zgłaszają błędy, a program, który je ignoruje, psuje się znacznie później i w dużo mniej czytelny sposób.

Najczęściej zadawane pytania

Czym jest biblioteka standardowa C?

To zestaw funkcji, typów i makr, które dostarcza każda zgodna ze standardem implementacja C, podzielony na około 30 nagłówków. Obejmuje wejście i wyjście (<stdio.h>), pamięć i konwersje (<stdlib.h>), napisy (<string.h>), matematykę (<math.h>), czas, klasyfikację znaków i limity typów liczbowych. C nie ma wbudowanej obsługi wejścia i wyjścia ani napisów: wszystko to pochodzi stąd.

Czym różni się stdio.h od stdlib.h?

<stdio.h> to wejście i wyjście: printf, scanf, fopen, fgets, FILE. <stdlib.h> to ogólne narzędzia: malloc i free, atoi i strtol, rand i srand, exit, qsort, bsearch. Typowy program dołącza oba.

Do czego służy ctype.h?

Klasyfikuje i konwertuje pojedyncze znaki: isdigit, isalpha, isalnum, isspace, isupper, islower, ispunct, a do tego toupper i tolower. Używanie ich zamiast ręcznych porównań w stylu c >= '0' && c <= '9' jest czytelniejsze i poprawne dla każdych ustawień regionalnych i zestawu znaków.

Czy trzeba coś linkować, żeby używać biblioteki standardowej C?

Nie, z jednym wyjątkiem: funkcji matematycznych. Standardowa biblioteka C jest linkowana automatycznie, ale na Linuksie implementacje z <math.h> leżą w osobnej bibliotece, więc sqrt i pokrewne potrzebują -lm na końcu polecenia kompilacji. Wszystko inne wymaga tylko właściwego #include.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ