Bu soru-cevap bölümüne birkaç kez rastladım ve daha kapsamlı bir cevap vermek istedim. Bu konuda düşünmek için en iyi yol olduğunu düşünüyorum nasıl arayana hataları dönün ve için neler iade.
Nasıl
Bir işlevden bilgi döndürmenin 3 yolu vardır:
- Geri dönüş değeri
- Bağımsız Değişken (ler)
- Bant Dışı, yerel olmayan goto (setjmp / longjmp), dosya veya genel kapsamlandırılmış değişkenler, dosya sistemi vb.
Geri dönüş değeri
Değeri yalnızca tek bir nesne olarak döndürebilirsiniz, ancak rastgele bir kompleks olabilir. Aşağıda hata döndürme işlevi örneği verilmiştir:
enum error hold_my_beer();
Dönüş değerlerinin bir yararı, daha az müdahaleci hata işleme için çağrıların zincirlenmesine izin vermesidir:
!hold_my_beer() &&
!hold_my_cigarette() &&
!hold_my_pants() ||
abort();
Bu sadece okunabilirlikle ilgili değil, aynı zamanda bu tür fonksiyon işaretleyicilerinin bir dizisinin muntazam bir şekilde işlenmesine de izin verebilir.
Bağımsız Değişken (ler)
Bağımsız değişkenler aracılığıyla birden fazla nesne üzerinden daha fazla geri dönebilirsiniz, ancak en iyi uygulama toplam bağımsız değişken sayısını düşük tutmanızı önerir (örneğin, <= 4):
void look_ma(enum error *e, char *what_broke);
enum error e;
look_ma(e);
if(e == FURNITURE) {
reorder(what_broke);
} else if(e == SELF) {
tell_doctor(what_broke);
}
Bant dışı
Setjmp () ile bir yer ve int değerini nasıl işlemek istediğinizi tanımlarsınız ve kontrolü bir longjmp () aracılığıyla o konuma aktarırsınız. Bkz . C'de setjmp ve longjmp'nin pratik kullanımı .
Ne
- Gösterge
- kod
- Nesne
- Geri aramak
Gösterge
Bir hata göstergesi sadece bir sorun olduğunu söyler, ancak söz konusu sorunun doğası hakkında hiçbir şey yoktur:
struct foo *f = foo_init();
if(!f) {
/// handle the absence of foo
}
Bu, bir işlevin hata durumunu bildirmek için en az güçlü yoldur, ancak arayan hataya yine de dereceli bir şekilde yanıt veremezse mükemmeldir.
kod
Bir hata kodu arayan kişiye sorunun niteliği hakkında bilgi verir ve uygun bir yanıta (yukarıdan) izin verebilir. Dönüş değeri veya bir hata bağımsız değişkeninin üzerindeki look_ma () örneği gibi olabilir.
Nesne
Bir hata nesnesiyle, arayan rastgele karmaşık sorunlar hakkında bilgilendirilebilir. Örneğin, bir hata kodu ve uygun bir insan tarafından okunabilir mesaj. Arayan kişiye, birden çok şeyin yanlış gittiğini veya bir koleksiyonu işlerken öğe başına bir hata olduğunu bildirebilir:
struct collection friends;
enum error *e = malloc(c.size * sizeof(enum error));
...
ask_for_favor(friends, reason);
for(int i = 0; i < c.size; i++) {
if(reason[i] == NOT_FOUND) find(friends[i]);
}
Hata dizisini önceden ayırmak yerine, elbette gerektiği gibi dinamik olarak da yeniden atayabilirsiniz.
Geri aramak
Geri arama, hataları işlemenin en güçlü yoludur, çünkü işleve bir şeyler ters gittiğinde görmek istediğiniz davranışları söyleyebilirsiniz. Her işleve bir geri çağrı argümanı eklenebilir veya yalnızca aşağıdaki gibi bir yapının örneği başına özelleştirme gerekiyorsa:
struct foo {
...
void (error_handler)(char *);
};
void default_error_handler(char *message) {
assert(f);
printf("%s", message);
}
void foo_set_error_handler(struct foo *f, void (*eh)(char *)) {
assert(f);
f->error_handler = eh;
}
struct foo *foo_init() {
struct foo *f = malloc(sizeof(struct foo));
foo_set_error_handler(f, default_error_handler);
return f;
}
struct foo *f = foo_init();
foo_something();
Bir geri aramanın ilginç bir yararı, birden çok kez çağrılabilmesidir ya da mutlu yolda herhangi bir ek yükün bulunmadığı hataların yokluğunda hiç bir şekilde çağrılamaz.
Bununla birlikte, kontrolün ters çevrilmesi söz konusudur. Arama kodu geri aramanın başlatılıp başlatılmadığını bilmiyor. Bu nedenle, bir gösterge kullanmak da mantıklı olabilir.