【问题标题】:Variable name to string in function call, C++函数调用中的变量名到字符串,C++
【发布时间】:2015-11-05 07:10:55
【问题描述】:

我正在扩展我们的内部调试库,但遇到了奇怪的问题。我想将变量名输出为字符串。从这个站点上的elsewhere,我发现可以在文件中使用宏来执行此操作:

#define VarToStr(v) #v
...
printf("%s\n", VarToStr(MatName));

这会输出MatName。但是现在让我们通过一个跨文件的函数来试试这个(矩阵是一个定义的类型):

// DebugHelpers.h
#define VarToStr(v) #v
...
void PrintMatrix(const Matrix &InputMat)
{
    printf("%s\n", VarToStr(InputMat));
    ... // output InputMat contents
}

// DataAnalysis.cc
#include DebugHelpers.h
...
void AnalysisSubProgram342()
{
    Matrix MatName;
    ...
    PrintMatrix(MatName);
}

这会输出InputMat,而不是MatName。另一个文件中的函数如何从调用文件中获取变量名?

虽然更复杂的解决方案(包装类等)对更大的社区有用,但我的实现需要尽量减少对预先存在的代码/类的影响。


更新:

受 zenith 的 cmets 的启发,为了比较,我实施了他提出的两个解决方案,并且都快速运行。该宏适用于简单的输出,而该函数允许更复杂的工作(和类型检查/重载)。我不知道预处理器宏会如此复杂。我会记住两者以备将来使用。谢谢!

【问题讨论】:

  • 不可能。 InputMat 被称为 InputMat,不管它的值来自哪里。
  • C/C++ 未定义,因为没有排序点(除非您已重载 ++),
  • @Bathsheba 哈!好一个:p
  • @Bathsheba:(很好!)重载只能是 C++,所以可以删除 C 标签?
  • “#”将您作为前缀的文本字符串化;它是一个预处理器功能,不了解范围或数据类型,因此您不能将其用于您所描述的内容。

标签: c++


【解决方案1】:

你不能。 C 和 C++ 在运行时都不会保留变量名。

您的所有宏所做的只是替换编译时发生的文本。

【讨论】:

    【解决方案2】:

    正如其他人所提到的,C++ 不支持运行时反射,所以如果你想要一个字符串,它的内容只能在运行时知道(这是对 PrintMatrix 的调用发生的时候),你需要 将其作为参数传递。

    而且因为您始终知道变量的名称是什么,所以您不需要 VarToStr 宏:

    // DebugHelpers.h
    void PrintMatrix(const Matrix &InputMat, const char* MatName)
    {
        printf("%s\n", MatName);
        ... // output InputMat contents
    }
    
    // DataAnalysis.cc
    #include DebugHelpers.h
    ...
    void AnalysisSubProgram342()
    {
        Matrix MatName;
        ...
        PrintMatrix(MatName, "MatName");
    }
    

    但还有另一种选择:将PrintMatrix 本身设为宏,因为无论如何它只是一个调试对象:

    // DebugHelpers.h
    #define PRINT_MATRIX(InputMat)\
    printf(#InputMat "\n");\
    ... // output InputMat contents
    
    
    // DataAnalysis.cc
    #include DebugHelpers.h
    ...
    void AnalysisSubProgram342()
    {
        Matrix MatName;
        ...
        PRINT_MATRIX(MatName);
    }
    

    现在经过预处理,AnalysisSubProgram342 将如下所示:

    void AnalysisSubProgram342()
    {
        Matrix MatName;
        ...
        printf("MatName\n");
        ... // output InputMat contents
    }
    

    【讨论】:

    • 加一个,如果有的话,使用const char*
    • And because you always know what your variables' names are you don't need the VarToStr macro ... 使用工具重构时,字符串可能会更新,也可能不会更新。
    【解决方案3】:

    通常你不能这样做(在运行时获取变量的名称,例如从它的地址或在 C++ 中它的引用)。

    我专注于 Linux:

    但是,在 Linux(和基于 GNU glibc 的系统)上,对于 全局 变量(和函数),您可以使用 GNU 特定的 dladdr(3) 函数。

    如果所有相关代码都使用-g 编译(以获取调试信息),您可能会以DWARF 格式解析调试信息(可能也使用__builtin_frame_address 等)。费了些力气,您也许可以从call stack 上的地址中获取一些局部变量的名称。这将是一项重大的工作(可能需要几个月的工作)。 Ian Taylor 的libbacktrace(在 GCC 内部)可能会作为一个有用的起点。

    你也可以开始(假设一切都是用-g编译的),例如popen(3),一个gdb -p调试进程。

    请注意,最近的 GDB 调试器可以在 Python 或 Guile 中编写脚本,因此实际上为 GDB 开发 Python 或 Guile 函数会更快。

    您也可以简单地添加调试输出,例如here

    【讨论】:

      猜你喜欢
      • 2010-11-10
      • 2013-02-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-27
      相关资源
      最近更新 更多