【发布时间】:2016-09-05 20:30:42
【问题描述】:
请帮我解决这个问题。这是在 C 中获取行号、文件名和 var args 的示例代码。当我尝试运行它时,出现了一些错误。我相信有很多方法可以做到这一点。但是我必须使用现有的代码来实现一些功能。任何帮助或建议将不胜感激。
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#define MY_MACRO1(fmt, args...) \
{ \
char buf_d[1024]; \
MY_MACRO2(__FILE__, __LINE__,call_func(buf_d,sizeof(buf_d),fmt,##args)); \
}
#define MY_MACRO2(__FILE__, __LINE__,fmt, ...) printf("%s : %d -> %s : \n",__FILE__, __LINE__, __VA_ARGS__);
char * call_func(char *buf_t, size_t size, const char *fmt, ...)
{
va_list ap;
va_start(ap,fmt);
vsnprintf(buf_t, size, fmt, ap);
va_end(ap);
return buf_t;
}
int main()
{
printf("\n Now I am printintg macro....\n");
MY_MACRO1("Macro is working fine..\n");
return 0;
}
输出:
请查找宏扩展。宏中的最后一个参数(func 返回值)丢失。
char buf_d[1024];
printf("%s : %d -> %s : \n","file.c",35, );;
错误:
file.c:35:83: error: expected expression
{ char buf_d[1024]; printf("%s : %d -> %s : \n","file.c", 35, );; };
^
产生 1 个错误。
【问题讨论】:
-
大象:为什么要使用宏?
-
为什么在 C 和 C++ 都不是的情况下对它进行双重标记?您正在使用问题中未指定的编译器的非标准编译器扩展。它必须成为有效的C吗?它必须成为有效的 C++ 吗?它是否必须为您的特定编译器所接受?这三个都会给你不同的答案。又为什么选择将
__FILE__和__LINE__重新定义为宏参数?! -
IIRC
fmt ,args...后跟,##args是一个不可移植的扩展。您可以使用...代替fmt ,args...和__VA_ARGS__代替fmt,##args -
在宏中放置这样的缓冲区会带来一大堆麻烦。至少,用 do{}while(0) 包围它 - 但即便如此,这也让我很困扰。
-
所以我们用宏来调用一个宏,在其参数中重新定义系统宏并分配栈内存,来调用一个使用可变参数的函数。会出什么问题?我现在要逃跑了。