【问题标题】:generic way to print out variable name in c++在 C++ 中打印出变量名的通用方法
【发布时间】:2011-10-01 03:58:34
【问题描述】:

给定一个班级

struct {
  int a1;
  bool a2;
  ...
  char* a500;
  ...
  char a10000;      
}

我想打印或流出

"a1 value is SOME_VALUE"  
"a2 value is SOME_VALUE"
"a500 value is SOME_VALUE"
...
"a10000 value is SOME_VALUE"

成员变量的类型不一样(主要是int、bool、char*等,即不需要重载

感谢任何cmets!

【问题讨论】:

  • 一些框架 add reflection 但这不是原生语言功能
  • 在 C++ 中没有通用的方法来做你想做的事。您应该问自己是否使用了正确的工具来完成这项工作。考虑另一种语言,或 C++ 中的不同数据结构,可能是向量或列表。
  • 此外,你真的不能正确地做到这一点。以struct { std::string a; } 为例——你真的希望它打印出a._BUF[0] = 'H' a._BUF[1] = 'e' a._BUF[2] = 'l' , a._BUF[0] = 'l' 等等吗?还是您更愿意 a = "Hello, world\n" ? C++ 对如何打印struct Foo 有一个清晰的概念,那就是operator<<(std::ostream&, Foo);

标签: c++ variables printf iostream


【解决方案1】:

你可以使用邪恶的宏:

#define DUMP(a) \
    do { std::cout << #a " is value " << (a) << std::endl; } while(false)

使用示例(编辑现已更新为结构成员示例):

#include <iostream>

#define DUMPSTR_WNAME(os, name, a) \
    do { (os) << (name) << " is value " << (a) << std::endl; } while(false)

#define DUMPSTR(os, a) DUMPSTR_WNAME((os), #a, (a))
#define DUMP(a)        DUMPSTR_WNAME(std::cout, #a, (a))

struct S {
    int a1;
    float a2;
    std::string a3;

    std::ostream& dump(std::ostream& os)
    {
        DUMPSTR(os, a1);
        DUMPSTR(os, a2);
        DUMPSTR(os, a3);
        return os;
    }
};

int main()
{
    S s = { 3, 3.14, "  03.1415926" };

    s.dump(std::cout);

    DUMP(s.a1);
    DUMP(s.a2);
    DUMP(s.a3);

    return 0;
}

观看直播demo on CodePad

为什么是有趣的宏?

回答未提出的问题。考虑如果将宏调用嵌套在条件循环或 for 循环中会发生什么。 Marshall Cline explains the rest

【讨论】:

  • 是的。有时需要一个邪恶的宏来修补语言中的许多漏洞。
  • 您好,谢谢您的回答。但是您仍然需要键入 a1, a2, a3, ... ,这与 'printf ("a1 ..."); 相比没有很大的改进或通用方法; printf ("a2 ..."); ...'。如果我有 10, 000 个变量怎么办?
  • Ermmm... 那你就... (a) 搞砸了 (b) 做错了什么。结构中的 10,000 个变量:您应该使用容器。另外,查看序列化框架(它们仍然不打印成员名称,但我认为这是您的类的设计问题)
  • 嗨,嘿,似乎不存在通用方法。我为这个宏投票赞成你的帖子,但接受 unwind 的回答以指出反思。 :-)
  • “有趣的宏”下的链接似乎已损坏。为什么它是“邪恶的”?
【解决方案2】:

您要查找的功能通常称为reflection。它不是 C++ 的一部分,因为在编译语言中,您所追求的信息(人类可读的变量名称)通常不会由编译器保存。它不需要运行代码,因此包含它没有意义。

调试器通常可以检查带外符号信息或为此目的而保存在二进制文件中的符号数据,以显示此类名称,但为此重新执行此操作可能比其价值更多。

我建议自己寻找许多“技巧”(=解决方案)来实现这一点。

【讨论】:

  • 古老的pstruct command 解析gcc -g -s 的输出以获取可用形式的信息。它旨在与 perl 一起使用,但您可以将它用于这种类型的方法
【解决方案3】:

watch 宏是有史以来最有用的技巧之一。

#define watch(x) cout << (#x) << " is " << (x) << endl

如果您正在调试代码,watch(variable); 将打印变量的名称及其值。 (这是可能的,因为它是在预处理期间构建的。)

【讨论】:

    【解决方案4】:

    这是不可能的(见其他答案)。

    一个解决方法是使用自动代码生成。您将字段定义写入文件,然后从中生成 .h 和 .cpp 文件。我将它用于包含大约 100 个类和很多字段的代码。它能够生成将它们发送到流(主要是调试)和套接字通信的代码。它非常可靠(无需测试任何这些功能),但由于它不是纯 C++,它可能不适合您。

    【讨论】:

    • 如果您 (a) 不想或不能使用外部库并且 (b) 有太多类/结构成员无法合理复制,这可能是最好的方法- 手动粘贴宏(sehe's answer)。 (或者如果结构/类代码经常更改并且您担心有人最终会犯复制粘贴错误。)
    【解决方案5】:

    在 C++ 中无法枚举类的成员,因为在 C++ 中没有反射。所以你不能访问变量名。

    您可以使用指向成员的指针...

    void PrintMemberValue(int MyClass::*p, MyClass const & obj)
    {
        cout << "Member has value " << obj.*p;
    }
    
    MyClass obj;
    int MyClass::*p = &MyClass::a1;
    PrintMemberValue(p, obj);
    p = &MyClass::a2;
    PrintMemberValue(p, obj);
    etc
    

    【讨论】:

      【解决方案6】:

      GDB 可以打印结构。此脚本生成 gdb 脚本以在 gdb_print 指定的位置设置断点和打印值:

      gdb-print-prepare()
      {
      
          # usage:
          # mark print points with empty standalone defines:
          # gdb_print(huge_struct);
          # gdb-print-prepare $src > app.gdb
          # gdb --batch --quiet --command=app.gdb $app
          cat  <<-EOF
          set auto-load safe-path /
          EOF
          grep --with-filename --line-number --recursive '^\s\+gdb_print(.*);' $1 | \
          while IFS=$'\t ;()' read line func var rest; do
              cat  <<-EOF
              break ${line%:}
              commands
              silent
              where 1
              echo \\n$var\\n
              print $var
              cont
              end
              EOF
          done
          cat  <<-EOF
          run
          bt
          echo ---\\n
          EOF
      }
      

      来自https://gitlab.com/makelinux/lib/blob/master/snippets/gdb-print-prepare.md

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-08
        • 1970-01-01
        • 1970-01-01
        • 2015-09-11
        • 1970-01-01
        • 2012-10-21
        相关资源
        最近更新 更多