我在vanilla C :
中有以下宏功能#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
如果调用者省略format_string,如何修改函数以打印所有局部变量? e.g。
GLOG();
可能会打印
do_count:counter.c!123 count=456, message="Hello world", array=[7, 8] structure={ptr=0xACE0FBA5E, coord={x=9, y=0}}
如果不可能,我该怎样修改它才能打印当前的功能,文件和行号? e.g。
do_count:counter.c!123
原样,这会返回错误:
错误:','标记
之前的预期表达式
因为strncat
行只是
strncat(format, , 248);
答案 0 :(得分:4)
首先,由进程本身在运行时检查所有局部变量似乎是不可能的,因为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__
,因为后者是非标准的。
答案 1 :(得分:2)
我在this回答中找到this个链接。它可能会帮助您解决问题的第一部分。
第二,如何获得所有局部变量,即使不是不可能,也要困难得多。原因是代码在编译时实际上没有变量,它只是偏移到内存区域(堆栈)。你的编译器可能有内部函数可以用来检查堆栈,但是那么你只有可能的值而不是变量的名称。我认为唯一的解决方案是使用特殊的预处理器宏来声明局部变量,然后是一个结构列表来表示内省,这将是很多运行时和内存开销。
答案 2 :(得分:1)
正如其他人提到的,C没有反射功能,因此您无法在宏调用中捕获局部变量。话虽这么说,如果你想要一个宏有条件地发生取决于宏调用是否有任何参数(即你的“非null”和“null”参数),那么你可以做类似的事情以下内容:
#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 */ }
答案 3 :(得分: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)
如果省略参数,则使用预处理程序的字符串连接来简单地连接空字符串。
此外,我添加了do {...} while(0)以吞下尾随分号,以便以下if ... else有效:
if (...)
GLOG();
else
/* do something else */
(来自http://gcc.gnu.org/onlinedocs/cpp/Swallowing-the-Semicolon.html的想法)。