在c ++中打印变量名的通用方法

时间:2011-07-08 10:09:04

标签: c++ variables printf iostream

给出一个课程

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 *等,即不需要重载<< operator),成员变量名可以用任何东西命名,即,没有规则可循。而不是一个一个地明确地打字(非常繁琐且容易出错的工作),有没有通用的方式?

感谢您的任何评论!

6 个答案:

答案 0 :(得分:14)

你可以使用邪恶的宏:

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

用法示例(编辑现在已更新为struct成员的示例):

#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

答案 1 :(得分:8)

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

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

我建议你自己寻找一些“技巧”(=解决方案)来实现这个目标。

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

由于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

答案 4 :(得分:0)

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

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

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

答案 5 :(得分:0)

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