2014-12-26 14 views
7

C99'da (ve GNU uzantıları aracılığıyla) varyantik makroların eklendiğini biliyorum.Varyant makroları ANSI C

böyle bir şey ile geldim ANSI C. güzel bir alternatif var olup olmadığını merak ettik, ama yine de biraz garip:

böyle çağrılabilir Böylece
void log_info(const char *file, int line, const char *fmt, ...) 
{ 
#ifdef DEBUG 
    va_list ap; 
    char newfmt[1024] = { 0 }; 
    va_start(ap, fmt); 
    sprintf(newfmt, "[INFO] (%s:%d): %s\n", file, line, fmt); 
    vfprintf(stderr, newfmt, ap); 
    va_end(ap); 
#endif 
} 

Bu:

log_info(__FILE__, __LINE__, "info message: %s %d", "helloworld", 12); 

bu yaklaşımla yanlış bir şey ancak bunu yapmanın daha güzel bir yol olup olmadığını merak ediyorum, yoktur? Örneğin. her zaman dosya/satır belirtmeye gerek yok.

Herhangi bir geri bildirim için teşekkür ederiz.

Düzenleme: Burada ANSI C ile C89 demek istiyorum.

Düzenleme: Aşağıdaki yanıt gayet iyi ama inanıyorum ki, yazdırma komutunun çalıştırılmasını gerektirdiğinden, bazı iş parçacığı güvenliği sorunları olabileceğinden emin olabilirsiniz.

#define __FL__ __FILE__, __LINE__ 

ve benzeri komutu: Diğer bir alternatif (aynı zamanda oldukça çirkin) yazarak en aza indirmek için tanımlar kullanmak olabilir

log_info(__FL__, "info message: %s %d", "helloworld", 12); 
+0

Ne tür bir durumda, varyantik makroları desteklemeyen bir derleyiciyle C yazıyor olabilirsiniz? –

+1

@Alexis King: Yanıt için teşekkürler. Örneğin, C89 bir şirket standartları veya belirli bir proje tarafından bir gereksinim olduğunda mı? Derleyicilerin çoğunun -ansi bayrağıyla bile kodu derleyeceğini biliyorum ve sorum, neden umursamam gerektiği değil, bu tür kısıtlamalar altında olsam ve yine de işlevselliğe ihtiyaç duyarsam ne yapmalıyım? Daha çok merak konusu, kabul etmeliyim. – Alex

+2

Arabellek taşmaları önlemek için lütfen snprintf (newfmt, sizeof (newfmt), "…",…) 'kullanın. Yine de (ikinci düşüncelerde), eğer C99'unuz yoksa, snprintf() 'e sahip olmayabilirsiniz. Bu tam olarak doğru değil - MSVC çoğunlukla C89 ama kütüphaneler arasında snprintf() bulunur. En azından, eğer yapabiliyorsanız 'snprintf()' kullanın. –

cevap

16

Biraz çirkin ama bir dizi var virgülle ayrılmış Parantez içindeki ifadeler tek bir argüman olarak ele alınabilir.

Bir örnek:

#include <stdio.h> 

#define LOG(args) (printf("LOG: %s:%d ", __FILE__, __LINE__), printf args) 

int main(void) { 
    LOG(("Hello, world\n")); 
    int n = 42; 
    LOG(("n = %d\n", n)); 
    return 0; 
} 

çıkışı: Bu çağrıda parantez fazladan bir dizi gerektirir

LOG: c.c:6 Hello, world 
LOG: c.c:8 n = 42 

Not. İşte

+0

Teşekkürler. İlginç. – Alex

+1

Bu yaklaşımla ilgili tek uyarı, birden çok iş parçacıklı uygulamalarda bazı sorunlar yükleyebileceğimi düşündüğüm iki kez printf (veya başka bir yazdırma işlevi) çalıştırmanız GEREKMEKTEDİR. – Alex

+0

Sen bir hayat kurtarıcısın! –

3

daha çirkin bir seçenektir, ancak printf tek çağrı kullanır:

#define PROMPT "[INFO] (%s:%d): " 
#define FL __FILE__, LINE__ 

#define DEBUG0(fmt) printf(PROMPT fmt, FL); 
#define DEBUG1(fmt, a1) printf(PROMPT fmt, FL, a1); 
#define DEBUG2(fmt, a1, a2) printf(PROMPT fmt, FL, a1, a2); 
#define DEBUG3(fmt, a1, a2, a3) printf(PROMPT fmt, FL, a1, a2, a3); 

vb sizinle makro arama argümanlar çoğu sayısına kadar.

+0

Bunun için teşekkürler. İlk olarak oldukça garip olduğunu düşündüm ama daha fazla düşündüğümde çözümden daha çok hoşlanıyorum. Bunun tek kötü tarafı, bir çok tanımın yaratılması gerekliliğidir. – Alex

+1

@Alex evet, kurmak çok kötü ama bir başlık içinde gizlendiğinde diğer kaynak dosyalarınızda o kadar da kötü değil –

+0

Anlaştık. Sağol Matt. – Alex