C dilinde yerleşik istisna desteği yoktur, hata işleme şu şekillerde gerçekleştirilir:
Hata kodu döndürme (genellikle fonksiyonun dönüş değeri ile) Örnek:
int read_file(const char *name) { FILE *f = fopen(name, "r"); if (!f) return -1; // Hata // ... fclose(f); return 0; // Başarı }
Küresel değişken errno kullanımı
Hata durumunda standart fonksiyonlar genellikle küresel errno değişkenini ayarlar.
Örnek:
FILE *fp = fopen("nofile", "r"); if (!fp) { perror("Dosya hatası"); // errno sebebi belirtir }
setjmp/longjmp — "istisna" fırlatma mekanizması (çalışma bağlamı korunur ve geri yüklenir) Karmaşık durumlar için kullanılır (örneğin, farklı seviyelerde acil sonlandırma). Nadir kullanılır, çünkü kodu karmaşıklaştırır ve kaynak sızıntılarına yol açabilir.
#include <setjmp.h> jmp_buf buf; if (setjmp(buf) == 0) { // ... longjmp(buf, 1); // setjmp(...)'e geri döner } else { // Hata işleme }
Aşağıdaki kod ne çıktıyı verir?
#include <stdio.h> #include <setjmp.h> jmp_buf buf; void func() { longjmp(buf, 5); } int main() { int val = setjmp(buf); printf("val=%d\n", val); if (val == 0) func(); return 0; }
Cevap:
setjmp 0 döndürür ve func fonksiyonu çağrılır.longjmp(buf, 5) gerçekleşir, yürütme setjmp'e geri döner, bu sefer 5 döndürür.val=0
val=5
Hikaye Bir kütüphanede hata durumunda temizleme mekanizması yalnızca hata kodu ile baştan sona manuel olarak uygulanmıştır. Ancak programcı, geri dönüş değeri
setjmp/longjmpüzerinden bir callback'ten dönerken hatayı işlemekten unuttuğundan bellek sızıntıları ve dosya kilitlenmeleri oluştu.
Hikaye Bir ağ uygulamasında, socket işleminden sonra
errnokontrolü atlandı. Bu, önceki fonksiyonun yanlış eski bir değeri nedeniyle yanlış teşhisle sonuçlandı.
Hikaye Ekip, çok sayıda hata kodu geri dönüş noktası ile karmaşık bir iç içe geçiş uyguladı ancak dönüş değerleri konvansiyonlarına (sıfır/negatif değerler) uyulmadı. Bazı hatalar başarı olarak yorumlandı, bu da hizmetin öngörülemeyen arızalarına yol açtı.