Setiap fungsi di examplelib mengembalikan kode error sebagai enum exlib_status. Pada bagian ini, kita perdalam strategi error handling: kapan menggunakan kode error vs return value, bagaimana menyusun enum yang konsisten, dan bagaimana membantu pengguna memahami error yang terjadi.
Konsep #
Strategi error handling di C biasanya memilih satu dari tiga pola:
- Kode error sebagai return value — fungsi mengembalikan
intatau enum, hasil perhitungan lewat parameter output. Pola yang kita pakai diexamplelib. - Sentinel value — return value khusus menandai error (mis.
NULLuntuk pointer,-1untuk int). Pola ini dipakaigetchar()yang mengembalikanEOF. - Out-of-band error (errno) — variabel global
errnodi<errno.h>di-set saat error terjadi. Pola yang dipakai library standarfopen,strtol.
Pilihan kita: pola 1 untuk examplelib karena paling eksplisit dan type-safe. Pengguna langsung tahu dari return value apakah sukses atau error, dan tahu jenis error apa.
Mekanisme kerja: setiap fungsi publik mengembalikan exlib_status. Pemanggil wajib memeriksa return value sebelum memakai hasil. Kontrak “all-or-nothing”: bila return != EXLIB_OK, parameter output tidak diubah. Pola ini membuat kode pemanggil lebih aman:
double mean;
if (exlib_mean(data, n, &mean) != EXLIB_OK) {
/* mean tidak boleh dipakai di sini */
return;
}
/* mean aman dipakai */Implementasi #
Enum error yang dipakai di examplelib:
typedef enum {
EXLIB_OK = 0,
EXLIB_ERR_NULL = -1,
EXLIB_ERR_RANGE = -2,
EXLIB_ERR_FORMAT = -3,
EXLIB_ERR_OVERFLOW = -4,
EXLIB_ERR_NOT_FOUND = -5
} exlib_status;Fungsi exlib_strerror menerjemahkan kode ke pesan:
const char *exlib_strerror(exlib_status code) {
switch (code) {
case EXLIB_OK: return "sukses";
case EXLIB_ERR_NULL: return "pointer NULL atau n=0";
case EXLIB_ERR_RANGE: return "nilai di luar rentang valid";
case EXLIB_ERR_FORMAT: return "format input tidak valid";
case EXLIB_ERR_OVERFLOW: return "potensi overflow";
case EXLIB_ERR_NOT_FOUND: return "tidak ditemukan";
default: return "kode tidak dikenal";
}
}Pola penggunaan yang baik di sisi pemanggil:
/* demo_error_lib.c - Pola error handling yang baik */
#include <stdio.h>
#include <stdint.h>
#include "examplelib.h"
static void report(const char *op, exlib_status s) {
if (s == EXLIB_OK) {
printf("[OK] %s\n", op);
} else {
printf("[ERR] %s: %s (code=%d)\n",
op, exlib_strerror(s), (int)s);
}
}
int main(void) {
/* Kasus sukses. */
double data[] = {2.0, 4.0, 6.0};
double mean;
exlib_status s = exlib_mean(data, 3, &mean);
report("mean(data,3)", s);
if (s == EXLIB_OK) {
printf(" -> mean = %.2f\n", mean);
}
/* Kasus error: n=0. */
s = exlib_mean(data, 0, &mean);
report("mean(data,0)", s);
/* Kasus error: data NULL. */
s = exlib_mean(NULL, 5, &mean);
report("mean(NULL,5)", s);
/* Kasus error: buffer terlalu kecil. */
char buf[5];
s = exlib_format_size(1024, buf, sizeof(buf));
report("format_size(buf=5)", s);
/* Kasus error: substring tidak ditemukan. */
s = exlib_contains("hello", "world");
report("contains(hello,world)", s);
/* Kode tidak dikenal (seharusnya tidak terjadi di API normal). */
s = (exlib_status)999;
report("invalid_code_999", s);
return 0;
}Output yang Dihasilkan:
[OK] mean(data,3)
-> mean = 4.00
[ERR] mean(data,0): pointer NULL atau n=0 (code=-1)
[ERR] mean(NULL,5): pointer NULL atau n=0 (code=-1)
[ERR] format_size(buf=5): nilai di luar rentang valid (code=-2)
[ERR] contains(hello,world): tidak ditemukan (code=-5)
[ERR] invalid_code_999: kode tidak dikenal (code=999)Mari kita telaah baris-baris kode di atas:
- Baris 1-7 (enum dengan nilai eksplisit): Setiap error punya nilai negatif yang unik.
EXLIB_OK = 0sehinggaif (s)bekerja sebagai cek error (0 = false = sukses, non-zero = true = error). Pola ini konsisten dengan convention Unix exit code. - Baris 9-19 (
exlib_strerror): Switch case yang lengkap.defaultmenangani integer cast ke enum yang tidak valid. Pola ini defensif: bila pengguna lupa updatestrerrorsaat menambah enum baru, default memberi pesan yang masuk akal. - Baris 21-29 (
reporthelper): Helper di sisi pemanggil yang mencetak hasil dengan format konsisten. Bilas == EXLIB_OK, cetak [OK]; selain itu, cetak [ERR] dengan kode dan pesan. Helper seperti ini mengurangi boilerplate di kode pemanggil. - Baris 38-43 (kasus sukses): Setelah
exlib_meanreturn OK, kita bisa memakaimean. Bila return != OK,meantidak boleh dipakai (nilainya tidak terdefinisi). Kontrak ini harus dijaga oleh implementasi. - Baris 46-53 (kasus error): Berbagai input invalid memicu error berbeda. Pemanggil bisa
switch (s)untuk menangani error berbeda secara berbeda — mis. logika retry untukEXLIB_ERR_FORMAT, abort untukEXLIB_ERR_OVERFLOW. - Baris 60-61 (invalid code):
(exlib_status)999menguji default case. Pemanggil “nakal” bisa saja melewatkan integer acak keexlib_strerror. Default menangani dengan pesan “kode tidak dikenal” tanpa crash.
Kode Lengkap #
Kode lengkap dengan enum error, exlib_strerror, dan dokumentasi setiap kode ada di examplelib.h dan examplelib.c. README juga menyertakan tabel kode error untuk referensi cepat.
Pengujian #
Test error handling dengan berbagai skenario:
- Input NULL →
EXLIB_ERR_NULL. - Input dengan n=0 →
EXLIB_ERR_NULL(konvensi kita: n=0 dianggap “no data”). - Input dengan nilai di luar rentang (mis.
out_capterlalu kecil) →EXLIB_ERR_RANGE. - Input dengan format yang salah →
EXLIB_ERR_FORMAT. - Operasi yang menghasilkan substring tidak ditemukan →
EXLIB_ERR_NOT_FOUND. - Cast integer acak ke enum →
defaultcase di strerror.
gcc -std=c11 -Wall -Wextra -Iinclude -o /tmp/demo_error_lib \
demo_error_lib.c src/examplelib.c -lm
/tmp/demo_error_lib