Header <errno.h> menyediakan mekanisme standar C untuk melaporkan kesalahan dari fungsi library. Variabel global errno diisi dengan kode error spesifik bila sebuah fungsi gagal—misalnya EDOM bila input fungsi matematika di luar domain, ERANGE bila hasil di luar jangkauan tipe, ENOENT bila file tidak ditemukan, atau ENOMEM bila alokasi memori gagal. Header ini juga menyediakan konstanta kode error dan makro strerror (dari <string.h>) yang mengkonversi kode numerik menjadi teks. Pada chapter ini kita akan meninjau konstanta errno yang sering dipakai, cara memeriksa errno, dan pola penanganan error berbasis errno.
Konstanta errno Umum dan strerror #
Variabel errno bersifat thread-local sejak C11—setiap thread punya errno sendiri, jadi pesan error dari satu thread tidak menimpa yang lain. Kode error adalah bilangan bulat positif; nilai 0 berarti tidak ada error. Setiap pemanggilan fungsi library yang sukses tidak dijamin me-reset errno ke 0—karena itu kita harus selalu me-reset manual sebelum memanggil fungsi yang mungkin gagal.
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <math.h>
#include <stdlib.h> /* strtol */
int main(void) {
/* EDOM: domain error dari fungsi matematika */
errno = 0;
double r = sqrt(-1.0);
if (errno == EDOM) {
printf("sqrt(-1) gagal: EDOM (%d) - %s\n", errno, strerror(errno));
} else {
printf("sqrt(-1) = %f (tidak error)\n", r);
}
/* ERANGE: range error dari fungsi matematika atau strtol */
errno = 0;
long v = strtol("99999999999999999999999", NULL, 10);
if (errno == ERANGE) {
printf("strtol overflow: ERANGE (%d) - %s\n", errno, strerror(errno));
} else {
printf("strtol = %ld\n", v);
}
/* perror: cara singkat mencetak pesan error */
errno = ENOENT;
perror("File test");
errno = EACCES;
perror("Akses ditolak");
errno = ENOMEM;
perror("Kehabisan memori");
return 0;
}Output yang Dihasilkan (stdout):
sqrt(-1) gagal: EDOM (33) - Numerical argument out of domain
strtol overflow: ERANGE (34) - Numerical result out of rangeOutput yang Dihasilkan (stderr):
File test: No such file or directory
Akses ditolak: Permission denied
Kehabisan memori: Cannot allocate memoryMari kita telaah baris-baris kode di atas:
- Baris 9 (
errno = 0;): wajib me-reset sebelum pemanggilan fungsi yang akan diperiksa. Tanpa ini,errnobisa berisi sisa dari kegagalan sebelumnya yang tidak ada hubungannya dengan pemanggilan saat ini. - Baris 10-11 (
sqrt(-1.0); if (errno == EDOM)):sqrt(-1.0)adalah domain error—input di luar domain fungsi (bilangan negatif). Fungsi mengembalikan NaN dan menetapkanerrno = EDOM(kode 33 di sistem ini). - Baris 17 (
strtol("99...99", NULL, 10); if (errno == ERANGE)): string berisi angka terlalu besar untuklong.strtolmengembalikanLONG_MAXdan menetapkanerrno = ERANGE. - Baris 25 (
perror("File test")):perrormencetakprefix: strerror(errno)kestderr. Pola umum untuk mencetak pesan error setelah panggilan sistem gagal. - Baris 22 (
strerror(errno)): mengkonversi kode numerik ke string deskripsi yang dapat dibaca manusia. String ini biasanya statis—tidak perlu di-free.
Pola Wrapper: Memetakan Error ke errno #
Saat kita menulis fungsi sendiri, kita dapat mengikuti konvensi errno agar API konsisten dengan standard library. Fungsi wrapper berikut mengembalikan 0 bila sukses dan -1 bila gagal, dengan kode errno spesifik yang menjelaskan jenis kesalahan.
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
/* Fungsi wrapper yang memetakan kesalahan ke errno */
static int baca_file_config(const char *path, char *buf, size_t buf_size) {
if (path == NULL || buf == NULL) {
errno = EINVAL;
return -1;
}
if (buf_size < 64) {
errno = ERANGE;
return -1;
}
/* Simulasi: cek apakah "file" ada */
if (strcmp(path, "/etc/passwd") != 0) {
errno = ENOENT;
return -1;
}
snprintf(buf, buf_size, "config loaded from %s", path);
return 0;
}
int main(void) {
char buf[32]; /* terlalu kecil */
/* Kasus 1: buffer terlalu kecil */
if (baca_file_config("/etc/passwd", buf, sizeof(buf)) != 0) {
printf("Gagal (buf kecil): errno=%d (%s)\n", errno, strerror(errno));
}
/* Kasus 2: file tidak ada */
char buf2[128];
if (baca_file_config("/etc/tidak_ada", buf2, sizeof(buf2)) != 0) {
printf("Gagal (no file) : errno=%d (%s)\n", errno, strerror(errno));
}
/* Kasus 3: argumen NULL */
if (baca_file_config(NULL, buf2, sizeof(buf2)) != 0) {
printf("Gagal (NULL) : errno=%d (%s)\n", errno, strerror(errno));
}
/* Kasus 4: berhasil */
if (baca_file_config("/etc/passwd", buf2, sizeof(buf2)) == 0) {
printf("Sukses: %s\n", buf2);
}
return 0;
}Output yang Dihasilkan:
Gagal (buf kecil): errno=34 (Numerical result out of range)
Gagal (no file) : errno=2 (No such file or directory)
Gagal (NULL) : errno=22 (Invalid argument)
Sukses: config loaded from /etc/passwdFungsi baca_file_config mengembalikan 0 untuk sukses dan -1 untuk kegagalan—konvensi klasik C. Pemanggil memeriksa return value, dan bila gagal, membaca errno untuk mengetahui penyebab spesifik. Empat kode errno yang dipakai: EINVAL (argumen invalid, kode 22), ERANGE (buffer terlalu kecil, kode 34), ENOENT (file tidak ditemukan, kode 2), serta implicitly tidak ada error bila sukses. Pemanggil dapat langsung memakai strerror(errno) atau perror("prefix") untuk mencetak pesan tanpa harus tahu nilai numerik.
Daftar Konstanta errno Umum #
Berikut adalah daftar konstanta errno yang sering ditemui, beserta makna umumnya. Nilai numerik aktual bervariasi antar platform (POSIX vs Windows), jadi selalu rujuk nama simbolik:
| Konstanta | Makna | Sumber Umum |
|---|---|---|
EDOM | Domain error (input fungsi matematika) | sqrt(-1), log(-1) |
ERANGE | Range error (hasil di luar jangkauan tipe) | strtol overflow, exp(1000) |
EINVAL | Argumen invalid | Validasi parameter di wrapper |
ENOMEM | Tidak cuk memori | malloc gagal |
ENOENT | File atau path tidak ditemukan | fopen("file_tidak_ada", "r") |
EACCES | Permission denied | fopen("/etc/shadow", "w") |
EEXIST | File sudah ada | open(O_CREAT|O_EXCL) |
EAGAIN | Sumber daya sementara tidak tersedia | read pada non-blocking socket |
EINTR | Operasi diinterupsi sinyal | read saat SIGINT tiba |
EBADF | File descriptor buruk | read(fd_invalid, ...) |
EIO | I/O error fisik | Kerusakan disk |
EBUSY | Sumber daya sedang sibuk | Mount ulang saat dipakai |