首页 文章

将调用上下文GCC预处理器宏值传播到目标函数

提问于
浏览
1

比方说我有

foo () {
  bar ();
}

其中 foo 位于 f.cbar 位于 b.c ,即 b.h 包含在 f.c 中 . 我想修改 bar 以打印它从调用它的任何函数 foo 调用,如下所示:

bar () {
  printf ("Called from line %d in file %s",?,?);
  /* Run as usual */
}

我想从predefined GCC preprocessor macros __LINE____FILE__ 获取这两条信息 . 但是,如果只是插入 printf ,这些显然会分别评估 b.cprintf 的行和 b.c 的路径 .

我可以以某种方式将 __LINE____FILE__ 的值从调用上下文传播到 bar 中的 printf ,因此会打印"Called from line x in file foo.c"吗?

我试图将 bar 重命名为 bar2 ,然后在头文件_1008217中定义委托函数:

bar () {
  printf ("Called from line %d in file %s",__LINE__,__FILE__);
  bar2 ();
}

我们的想法是 #include 指令会将 Headers 代码复制到源文件 f.c 中,然后分别将路径替换为 f.c 和行号 . 但是,这给了我不同翻译单元的重复定义错误 .

接下来,我尝试将 static 修饰符添加到 bar2 的标头定义中,以允许多个定义 . 然后我可以编译没有错误并运行程序,但仍然只打印 bar.h .

我哪里错了?我确信有更优雅的方式来做到这一点 .

问题:

  • 为什么不使用像GDB这样的调试器?这是内核代码 .

  • 为什么不进行来电方调试?大代码库 .

编辑:

为什么这不起作用?

#ifdef DEBUG_PALLOC
#define palloc_get_page(FLAGS) (palloc_get_page_debug (FLAGS,  __FILE__,__LINE__))
#else
void *palloc_get_page (enum palloc_flags);
#endif

1 回答

  • 3

    你可以创建一个委托,但不是 .h 中的一个函数,因为 __FILE____LINE__ 将在 .h 中(并且 static 修饰符在这里没有帮助),但是有一个宏将在适当的位置展开并带有正确的文件&行信息

    #define bar2() bar(__FILE__,__LINE__)
    

    bar 应该接受文件和行参数:

    void bar(const char *file, int line)
    {
       printf ("Called from line %d in file %s",line,file);
    }
    

    gdb方法更复杂 . 这可能适用于:

    • 一个gdb脚本,用于打印当前断点位置/回溯并继续,

    • 一个触发断点的协作 bar 函数(在intel / Windows上:使用 Breakpoint 函数或 asm("int $3") 指令,如果设置了一个标志/ env.var告诉调试器已启用,但如果经常调用 bar ,这可能会减慢该计划很多)

    注意:如果要使其可激活或不激活,则会变得更加复杂,但通过设置命令行 -DDEBUG 标志,您可以进行以下打印:

    档案 bar.h

    #pragma once
    #ifdef DEBUG
    
    #define bar2() bar(__FILE__,__LINE__)
    void bar(const char *file, int line);
    
    #else
    void bar2();
    #endif
    

    档案 bar.c

    #include "bar.h"
    #include <stdio.h>
    
    #ifdef DEBUG
    void bar(const char *file, int line)
    #else
    void bar2()
    #endif
    
    {
    #ifdef DEBUG
       printf ("Called from line %d in file %s\n",line,file);
    #endif
       printf("NOP\n");
    }
    

    从主程序中调用 bar2 . 如果设置了 DEBUGbar2 是一个调用 bar 的宏 . 如果未设置 DEBUG ,则 bar2 直接是您的功能 .

    请注意,除非您使用脚本生成这些模式,否则对所有函数执行此操作非常繁琐 .

相关问题