geri

c/c++ için yüksek performanslı debug satırları

24/10/2009

bir yazımda gcc -D parametresi kullanarak debug satırlarının yalnızca debug modunda derlenmesini sağlayabileceğimizden bahsetmiştim. örnek olarak debug için kullanacağımız satırları aşağıdaki şekilde tanımlarsak:

#ifdef __debug__
printf("Uygulama modu: debug");
#endif

kodu gcc -D__debug__ parametresi ile derlediğimizde bu satır derlenecek ve çalışacak, aksi halde derlenmeyecektir. release modu için -D parametresini vermememiz yeterli olmakta. böylece release modunda bu satır hem boyut hem de performans açısından uygulamaya bir yük getirmiyor; çünkü bu modda bu satır derlenmiyor.

geçen zaman içerisinde debug loglarımı daha düzenli hale getirmek istedim. bu amaçla içinde bulunulan metod adını ve mesajı parametre olarak alan bir metod hazırladım. bu metod aldığı parametreleri uygun şekilde formatlayarak standart çıktıya yazıyor.

#ifdef __debug__
/*!
 * External method for debugging. Use this method to print out debug messages.
 */
extern void Debug(const char *aMethod, const char *aMessage){
    printf("\nCANAVAR.DEBUGGING.ENGINE: In Method '%s': %s", aMethod, aMessage);
}
#endif

başlangıçta verimli gibi görünen bu metodun zamanla eksikleri ortaya çıktı. printf() fonksiyonuna bir format stringi ve n adet parametre göndererek çıktıyı formatlayabiliyoruz ancak yazdığım bu metod yalnızca tek bir parametre alabiliyor. Biraz araştırma yaptıktan sonra Debug() metodunu n adet parametre alabilir ve aldığı parametreleri printf() fonksiyonuna geçirebilir hale getirdim. metod şu hale geldi:

#ifdef __debug__
#include <stdarg .h>
#include <stdio .h>
/*!
 * External method for debugging. Use this method to print out debug messages.
 */
extern void Debug(const char *aMethod, const char *aMessage, ...){
    va_list argp;
    printf("\nCANAVAR.DEBUGGING.ENGINE: In Method '%s': ", aMethod);
    va_start(argp, aMessage);
    vprintf(aMessage, argp);
    va_end(argp);
}
#endif
standart çıktıya debug satırları yazmak için bu metodu şu şekilde kullanabiliyoruz:
#ifdef __debug__
Debug("main", "Value of i: %d", 1);
#endif
bu satırın çıktısı şu şekilde oluyor:
CANAVAR.DEBUGGING:ENGINE: In method 'main': Value of i: 1

kodun geldiği bu son durum beni oldukça tatmin etmişti. ancak zamanla fark ettim ki debug satırlarını her zaman #ifdef __debug__ ve #endif satırları arasına almam gerekiyor. bu da her defasında fazladan iki satır anlamına geliyor. bu satırları Debug() metodunun içine almak sorunumu kısmen çözecekti ancak yan etkisi bir metod çağrısı için geçen işlem zamanı olacaktı. release modunda debug satırlarının ve Debug() metodunun en ufak bir etkisini görmek istemediğim için arkadaşım Mehmet Bilsay Karadeniz ile bilim yuvamızda biraz araştırma yaptık. kısa sürede şu sonuca ulaştık:

#ifdef __debug__
#define DEBUG(x) Debug x;
#else
#define DEBUG(x)
#endif
şeklinde bir macro hazırladık. böylece debug satırı için aşağıdaki kod yeterli hale geldi.
DEBUG(("main", "step 2; move %d; x=%f; rect.x: %d, rect.y: %d", i, x, rect.x, rect.y))
release modunda önişlemci bu satırı boşluk ile değiştiriyor. debug modunda ise aynı satır Debug("main", "step 2; move %d; x=%f; rect.x: %d, rect.y: %d", i, x, rect.x, rect.y); satırı ile değiştiriliyor. böylece kullanımı kolay ve yüksek performanslı bir debug yöntemi elde etmiş olduk.

Follow me on Twitter