C'de, açık hata işleme için if + goto'nun manuel kullanımı yoluyla otomatik "nesne düzeltme" ile birlikte istisnaları "simüle edebilirsiniz".
Genellikle aşağıdaki gibi C kodu yazarım (hata işlemeyi vurgulamak için kaynatılır):
#include <assert.h>
typedef int errcode;
errcode init_or_fail( foo *f, goo *g, poo *p, loo *l )
{
errcode ret = 0;
if ( ( ret = foo_init( f ) ) )
goto FAIL;
if ( ( ret = goo_init( g ) ) )
goto FAIL_F;
if ( ( ret = poo_init( p ) ) )
goto FAIL_G;
if ( ( ret = loo_init( l ) ) )
goto FAIL_P;
assert( 0 == ret );
goto END;
/* error handling and return */
/* Note that we finalize in opposite order of initialization because we are unwinding a *STACK* of initialized objects */
FAIL_P:
poo_fini( p );
FAIL_G:
goo_fini( g );
FAIL_F:
foo_fini( f );
FAIL:
assert( 0 != ret );
END:
return ret;
}
Bu tamamen standart ANSI C'dir, hata işlemeyi ana hat kodunuzdan ayırır, C ++ 'nın yaptığı gibi başlatılan nesnelerin (manuel olarak) yığın çözülmesine izin verir ve burada ne olduğu tamamen açıktır. Her noktada açıkça başarısızlık testi yaptığınız için, bir hatanın meydana gelebileceği her yere belirli bir günlük kaydı veya hata işlemeyi eklemeyi kolaylaştırır.
Biraz makro büyüsüne aldırış etmezseniz, yığın izleriyle hataları günlüğe kaydetmek gibi diğer şeyleri yaparken bunu daha kısa hale getirebilirsiniz. Örneğin:
#include <assert.h>
#include <stdio.h>
#include <string.h>
#define TRY( X, LABEL ) do { if ( ( X ) ) { fprintf( stderr, "%s:%d: Statement '" #X "' failed! %d, %s\n", __FILE__, __LINE__, ret, strerror( ret ) ); goto LABEL; } while ( 0 )
typedef int errcode;
errcode init_or_fail( foo *f, goo *g, poo *p, loo *l )
{
errcode ret = 0;
TRY( ret = foo_init( f ), FAIL );
TRY( ret = goo_init( g ), FAIL_F );
TRY( ret = poo_init( p ), FAIL_G );
TRY( ret = loo_init( l ), FAIL_P );
assert( 0 == ret );
goto END;
/* error handling and return */
FAIL_P:
poo_fini( p );
FAIL_G:
goo_fini( g );
FAIL_F:
foo_fini( f );
FAIL:
assert( 0 != ret );
END:
return ret;
}
Elbette bu, C ++ istisnaları + yıkıcılar kadar zarif değil. Örneğin, birden çok hata işleme yığınını bir işlevin içine bu şekilde yerleştirmek çok temiz değildir. Bunun yerine, muhtemelen hataları benzer şekilde işleyen kendi içinde alt işlevlere ayırmak istersiniz, açıkça böyle başlat + sonlandırmak istersiniz.
Bu aynı zamanda yalnızca tek bir işlev içinde çalışır ve daha yüksek seviyeli arayanlar benzer açık hata işleme mantığını uygulamadıkça yığını atlamaya devam etmez, oysa bir C ++ istisnası uygun bir işleyici bulana kadar yığını atlamaya devam eder. Ayrıca rastgele bir tür atmanıza da izin vermez, bunun yerine yalnızca bir hata kodu verir.
Bu şekilde sistematik olarak kodlama (yani - tek bir giriş ve tek çıkış noktası ile), ne olursa olsun çalıştırılacak pre ve post ("nihayet") mantığını eklemeyi de çok kolaylaştırır. "Nihayet" mantığınızı END etiketinin arkasına koyarsınız.