【问题标题】:Macro within macro in CC中的宏中的宏
【发布时间】: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) 包围它 - 但即便如此,这也让我很困扰。
  • 所以我们用宏来调用一个宏,在其参数中重新定义系统宏并分配栈内存,来调用一个使用可变参数的函数。会出什么问题?我现在要逃跑了。

标签: c function macros


【解决方案1】:

真是一团糟!让我们把东西清理干净:

代码:

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>


#define DEBUG_MSG( _msg, ... )  do {print_debug_msg( __FILE__, __LINE__, __FUNCTION__, _msg, ## __VA_ARGS__ ); }while(0)


void print_debug_msg( const char * module, int line, const char * func, const char * fmt, ... )
{
    va_list va;
    char buf[ 1024 ] = {0};

    va_start( va, fmt );
    vsnprintf( buf, sizeof(buf), fmt, va );
    va_end( va );

    printf( "%s:%d - %s() - %s\n", module, line, func, buf );
}


int myfunc( const char * msg )
{
    DEBUG_MSG( "Message: %s",  msg );

    return 0;
}


int main( int argc, char * argv[] )
{
    DEBUG_MSG("The quick brown fox jumps over the lazy dog.");

    DEBUG_MSG("Pack my box with five dozen liquor jugs.");

    myfunc( "How vexingly quick daft zebras jump" );

    myfunc("The five boxing wizards jump quickly.");

    return 0;
}

/* eof */

编译:

$ gcc -Wall macro.c -o macro

测试:

$ ./macro 
macro.c:32 - main() - The quick brown fox jumps over the lazy dog.
macro.c:34 - main() - Pack my box with five dozen liquor jugs.
macro.c:24 - myfunc() - Message: How vexingly quick daft zebras jump
macro.c:24 - myfunc() - Message: The five boxing wizards jump quickly.

参考资料:

1) Recommended C Style and Coding Standards (Macros)

2) GCC Manual - Standard Predefined Macros

希望对你有帮助!

【讨论】:

    【解决方案2】:

    当您使用, ... 时,这意味着您必须提供一个参数,这不是您的情况。您可以通过命名参数列表来修改您的宏,并让预处理器在需要时避开逗号:

    #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(F,L,fmt,args...)  printf("%s : %d -> %s : \n",F, L, fmt, ##args)
    

    【讨论】:

    • test_macro.c:30:2: 警告:比数据参数更多的 '%' 转换 [-Wformat] 我认为你是对的 Jean。但是当我尝试时,我收到了以下警告。它正在打印一些垃圾而不是所需的字符串..test_macro.c:20:69: 注意:从宏 'DEBUG_APMD_V2' #define DEBUG_APMD_V2(file, line,fmt, args... ) printf("%s : %d -> %s : \n",file, line, ##args); ~^ 生成 1 个警告。
    • 您按照我的建议修改的示例对我有用,可能您的实际情况有点不同?
    • 请注意,省略号前不带逗号的符号是 GCC(也可能是 Clang-for-compatibility-with-GCC)扩展。
    猜你喜欢
    • 1970-01-01
    • 2018-11-12
    • 1970-01-01
    • 2018-10-17
    • 2012-03-07
    • 1970-01-01
    • 1970-01-01
    • 2019-04-13
    • 1970-01-01
    相关资源
    最近更新 更多