c++中输出变量名的通用方法
generic way to print out variable name in c++
给定一个类
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*等),即不需要重载<<操作符),并且成员变量名可以用任何名称命名,即不需要遵循任何规则。除了一个接一个地显式键入(非常繁琐且容易出错的工作)之外,有没有通用的方法?
谢谢你的评论!
你可以使用一个邪恶的宏:
#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;
}
查看CodePad上的实时演示
为什么要用这个有趣的宏?
回答未被问到的问题。考虑一下如果将宏调用嵌套在条件循环或for循环中会发生什么情况。Marshall Cline解释了其余部分
您正在寻找的特性通常称为反射。它不是c++的一部分,因为在编译语言中,您所追求的信息(人类可读的变量名)通常不会被编译器保留。运行代码不需要它,所以没有必要包含它。
调试器通常可以检查带外符号信息,或者为了这个目的而保存在二进制文件中的符号数据,以显示这些名称,但是为了这个目的重新做这些工作可能比它的价值更多。
我建议你自己寻找一些"技巧"(=解决方案)来实现这个。
watch
宏是最有用的技巧之一。
#define watch(x) cout << (#x) << " is " << (x) << endl
如果您正在调试代码,watch(variable);
将打印变量的名称和它的值。(这是可能的,因为它是在预处理期间构建的。)
这是不可能的(参见其他答案)。
一个解决方法是使用自动代码生成。在一个文件中编写字段定义,然后从中生成.h和.cpp文件。我将此用于一个包含大约100个带有许多字段的类的代码。它能够生成将它们发送到流(主要是调试)和套接字通信的代码。它非常可靠(从来没有测试过这些功能),但由于它不是纯c++,它可能不适合您。在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
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
}
From https://gitlab.com/makelinux/lib/blob/master/snippets/gdb-print-prepare.md
- 你能重载对象变量名本身返回的内容吗
- 在C/C++中将变量名定义为__00000001有什么好处吗
- C++变量名(可以将 main 声明为变量,但对于其他函数名称则不然)
- C++ - 声明中变量名后面的括号
- 如何使替换 c 函数的变量名成为错误?
- 是否可以创建没有变量名的变量
- fstream库,试图创建一个变量名为(c++)的文件
- 一个数组C++中的消息和变量名
- 在变量名后声明带有 () 的非内部类型与不使用变量名的行为不同。即 std::map<int,char>x(); - 这是怎么回事?
- C++ 互斥锁可以交叉方法/变量吗?如果是这样,为什么在这里不起作用?
- 类方法变量,如果将它们存储在类本身中会更快吗?
- 数组的变量名和该数组的地址有什么区别?
- 将局部方法变量分配给类指针
- 如何将变量名设置为字符串?C++
- 类中具有相同变量名的多重继承
- 创建变量名别名的方法
- c++中输出变量名的通用方法
- 在编译时获取变量名的标准方法
- 方法定义中的变量名必须与C++中的声明名相同吗
- 当宏用作变量名时,是否有任何方法可以跳过宏替换(在预处理期间)