2011-10-31 110 views
2

我有香草Ç下面的宏功能:检测空参数在预处理宏

#define GLOG(format_string, ...) { \ 
    const char *file = strrchr(__FILE__, '/'); \ 
    char format[256] = "%s:%s!%d\t"; \ 
    strncat(format, format_string, 248); \ 
    strcat(format, "\n"); \ 
    printf(format, __FUNCTION__, file ? file : __FILE__, __LINE__, ##__VA_ARGS__); \ 
} 

,它可以让我打印包含当前函数,文件和行数,例如调试消息

GLOG("count=%d", count); 

可能会打印

do_count:counter.c!123 count=456 
  1. 如何修改打印所有局部变量,如果主叫方省略format_string中的作用?例如

    GLOG(); 
    

    可能会打印

    do_count:counter.c!123 count=456, message="Hello world", array=[7, 8] structure={ptr=0xACE0FBA5E, coord={x=9, y=0}} 
    
  2. 如果这是不可能的,我怎么可以修改它仅打印当前函数,文件和行号?例如作为strncat线简直是

    strncat(format, , 248); 
    

回答

3

首先,在进程本身检查所有局部变量似乎是不可能的,因为C没有任何反射手段。

其次,你会好得多,如果你写的日志宏这样的:

#include <stdio.h> 

#define STRINGIFY(x) #x 
#define TOSTRING(x) STRINGIFY(x) 

#define GLOGF(fmt, ...) \ 
    printf("%s:%s " fmt "\n", __func__, __FILE__ "!" TOSTRING(__LINE__), ##__VA_ARGS__) 

int main (void) { 
    /* main:test.c!xx count=5 */ 
    GLOGF("count=%d", 5); 
    /* main:test.c!xx */ 
    GLOGF(); 
    return 0; 
} 

它更简单,因为该字符串是在编译时串连不会产生任何额外的运行时开销。

另请注意,我用__func__而不是__FUNCTION__,因为后者是非标准的。

+0

感谢您的建议,但它并没有完全回答这个问题,因为GLOGF和GLOG是不同的功能,用户必须记住在这两种情况下使用哪一种。 – Gnubie

+0

@Gnubie:检查更新。如果这是你所需要的,你仍然可以调用'GLOGF()'并获得'main:test.c!xx'。 –

2

我发现this链接this答案

error: expected expression before ‘,’ token

do_count:counter.c!123 

原样,这将返回一个错误。它可以帮助你解决问题的第一部分。

第二,如何获取所有局部变量,如果不是不可能,则要困难得多。原因是代码在编译时实际上没有变量,它只是偏移到内存区域(堆栈)。您的编译器可能有可用于检查堆栈的内部函数,但可能那么你只有可能的值而不是变量的名字。我认为唯一的解决方案是使用特殊的预处理器宏来声明局部变量,然后使用一系列结构来表示它们以进行自省,这将在运行时和内存开销方面造成很大影响。

+0

谢谢,我怀疑C反射可能是不可能的。 – Gnubie

1

正如其他人在这里所说的,C没有反射特性,因此你不能在宏调用中捕获局部变量。这就是说,如果你想要一些条件性的宏发生,取决于宏调用是否存在任何参数(即,,你的“非空”和“空”参数),那么你可以做类似如下:

#include <string.h> 

#define NULL_IDENT "" 
#define IDENT(ident_name) #ident_name 
#define MACRO(ident_name) \ 
    if (strcmp(NULL_IDENT, IDENT(ident_name)) == 0) { \ 
     /* add code for a null argument passed to the macro */ } \ 
    else { \ 
     /* add code for a non-null argument passed to the macro */ } 
0

基于Blagovest Buyukliev的答案,我想出了以下解决方案,第2部分:

#define GLOG(fmt, ...) do { const char *fn = strrchr(__FILE__, '/');   \ 
    printf("%s:%s!%d\t"fmt"\n",__func__,fn?++fn:__FILE__,__LINE__,##__VA_ARGS__);\ 
} while(0) 

如果参数被省略,则使用预处理器的字符串连接简单地连接空字符串。

此外,我加入了做{...}而(0)吞尾随分号,这样,如果下面...别的办法:

if (...) 
GLOG(); 
else  
/* do something else */ 

(想法来自http://gcc.gnu.org/onlinedocs/cpp/Swallowing-the-Semicolon.html)。