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

问题描述 投票:0回答:6

上过课

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), and the member variable name could be named with anything, i.e., no rule to follow. Instead of typing explicitely one by one (very big tedious, and error-prone work), is there any generic way?

感谢您的任何评论!

c++ variables printf iostream
6个回答
21
投票

你可以使用邪恶的宏:

#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;
}

在 CodePad 上观看实时 演示

a1 is value 3
a2 is value 3.14
a3 is value   03.1415926
s.a1 is value 3
s.a2 is value 3.14
s.a3 is value   03.1415926

为什么是有趣的宏?

回答未提出的问题。考虑一下如果将宏调用嵌套在条件循环或 for 循环中会发生什么情况。 Marshall Cline 解释了其余部分


11
投票

您正在寻找的功能通常称为“反射”。它不是 C++ 的一部分,因为在编译语言中,编译器通常不会保留您所需要的信息(人类可读的变量名称)。运行代码不需要它,因此没有必要包含它。 调试器通常可以检查带外符号信息或出于此目的而保存在二进制文件中的符号数据,以显示此类名称,但为此目的重新执行此操作可能比其价值更多的工作。

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


6
投票
watch

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


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

如果您正在调试代码,
watch(variable);

将打印变量的名称及其值。 (这是可能的,因为它是在预处理期间构建的。)

    


1
投票

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

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


0
投票

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

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

0
投票

来自

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

© www.soinside.com 2019 - 2024. All rights reserved.