27 Aralık 2014 Cumartesi

C Macro'ları

C MACRO Notları

Macro'nun Tanımlı Olmasını Zorlamak
Örnek:
#if !defined MYMACRO
    #error "MYMACRO is not defined"
#endif

Sayı Sabitleri için Macrolar
Parantez içinde yazılması daha sağlıklı
#define INTMAX_MIN (-9223372036854775807LL)
#define INTMAX_MAX (9223372036854775807LL)

Fonksiyon Gibi Macrolar - Function Like Macros
C ile reflection yapmak mümkün değil ancak MACRO kullanarak bazı metodların işleyişini değiştirebilmek mümkün. Bu tür macrolara "function like macros" deniliyor. Örneğin bir fonksiyonu tanımsız hale getirebiliriz. Özellikle log'lama yeteneğini debug/release derlemeye göre değiştirebilmek için çok kullanışlı bir örnek aşağıda.
#ifdef LOG_ENABLED
 extern "C" void LOG_DEBUG (const char* data);
#else
 #define LOG_DEBUG(data); //Parantez ve macro arasında boşluk olmamalı
#endif

Bir başka yöntem ise boşa tanımlama. Örneğin assert macrosu Visual C++'ta aşağıdaki gibi tanımlı, dolayısıyla sadece debug derlemede çalışır.

#ifdef NDEBUG
    #define assert (_expression) ((void)0)
#endif

Macrolarda Yan Etkilere Dikkat Etmek
Macroları çağırırken, yan etkilere dikkat etmek gerekir. Örnekte aynı işi yapan iki farklı macro tanımlanmış.

Eğer bu macro max(i++,--j) şeklinde çağırılırsa, ilk macroda her a ve b tanımlaması için, istenenden daha fazla işleme sebep olur.

Macroların Parse Edilmesi
Macrolar preprocessor tarafından parse edilirler. Eğer macroya geçilen parametrede virgül karakteri varsa, birden fazla parametre geçiliyormuş gibi algılanabilir. Örnek'te template kullanıldığı için virgül hataya sebep oluyor.
TRAP_EXCEPTION
(
    (std::map<MyType, bool> Map;)
)
Bu gibi durumlarda macro içinde __VA_ARGS__ kullanılabilir.
#define TRAP_EXCEPTION(...) \
    try \
    { \
        try{ __VA_ARGS__ } \
        catch(Engine::Exception& e) \
        { \
            throw MyException(e.message()); \
        } \
    }

Stringification - String Haline Getirmek
Bu tür macrolarda ise macro'ya verilen parametre # işareti ile string haline getiriliyor. Bu yöntemin reflection'da nasıl kullanıldığını açıklamam lazım. Örnek:
Stringification ve Birleştirme
Parametreler #ile string haline getirilir, daha sonra birleştirme için kullanılan karakter string şeklinde araya yazılır. 
#define space_conc(str1,str2) #str1 " " #str2
space_conc(hello, world)) şeklinde çağırıldığında macro 
"hello" " " "world"
şeklinde açılır. Derleyici stringleri birleştirerek 
"hello world"
haline getirir.
Concatinaion - String haline getirmeden, sadece sembol olarak birleştirme
Bu tür macrolarda ise macro açıldıktan sonra ## işaretinin her iki yanındaki karakterler birleştirilir. Bu yöntemin reflection'da nasıl kullanıldığını açıklamam lazım. Örnek:
struct command
{
  char *name;
  void (*function) (void);
};

struct command commands[] =
{
  { "quit", quit_command },
  { "help", help_command },
  ...
};

#define COMMAND(NAME)  { #NAME, NAME ## _command }

struct command commands[] =
{
  COMMAND (quit),
  COMMAND (help),
  ...
};

Hiç yorum yok:

Yorum Gönder