问题提出
几天前,有人问了我这样一个问题:
我在调试 C++ 程序的时候,希望在代码中的一些位置输出某些变量以便于查找错误。
为了能够直观地在输出结果中分辨不同变量,要在输出每个变量之前先输出它的变量名。
比如,在输出一个变量 matrix1 的时候,我会使用这样的语句手动输出变量名:
cout << "matrixResult: " << matrixResult;
但是我感觉到每次输出变量时都要多写一遍变量名很繁琐,有没有更简洁的输出方式呢?
我此前并没有遇到过这样的需求,也不认为提问者所述的手动输出变量名是非常繁琐的做法,但是也感觉到这是一个挺有趣的问题。如何较为优美地在 C++ 中实现输出变量名呢?C++ 语言似乎并没有提供能够获取变量名的函数或类似的接口,但我搜索到了一个使用 C++ 的宏输出变量名的有些 tricky 的方法。
实现方式
在 C/C++ 语言的带参数的宏中,#
的作用是将宏的参数转化为一个字符串,即将 #
后的参数进行替换后在两端添加 "
,因此我们可以定义如下的宏:
1 |
#define VName(x) #x |
定义了这个宏之后,在代码中写 VName(matrixResult)
, 这一部分将会在代码编译前预处理时被替换为 "matrixResult"
,于是我们就获取了其变量名的字符串形式。进一步地,我们定义下面的宏,以及一个调试时输出变量的函数。
1 2 3 4 5 6 |
#define Print(x) PrintWithVariableName(#x, (x)) template<class T> void PrintWithVariableName(std::string vName, const T &x) { std::cout << vName << ": " << x << std::endl; } |
其中,函数 PrintWithVariableName
写成函数模板的形式,适用于 int
等原有数据类型,也适用于所有重载了流输出运算符 operator<<
的自定义类。这样,只要在代码中使用 Print(x)
,就可以将 x
的变量名与其值一起输出,我认为这是一种还算简洁的实现方式。
下面是一段完整的示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
#include <iostream> #include <string> #define Print(x) PrintWithVariableName(#x, (x)) template<class T> void PrintWithVariableName(std::string vName, const T &x) { std::cout << vName << ": " << x << std::endl; } class Student { public: std::string name; int studentNumber; double grade; friend std::ostream& operator<< (std::ostream &os, const Student &rhs) { os << "[" << rhs.name << ", " << rhs.studentNumber << ", " << rhs.grade << "]"; return os; } }; int main() { int integerA = 5; Student newSudent; newSudent.name = "Preston"; newSudent.studentNumber = 21006; newSudent.grade = 4.2; Print(integerA); Print(newSudent); Print(3 + 5 * 2); return 0; } |
运行这段程序,输出结果为:
1 2 3 |
integerA: 5 newSudent: [Preston, 21006, 4.2] 3 + 5 * 2: 13 |
赞
贊
%%%
%%
博客居然变样了哎
换了个VPS重新搭了一下,外观略有改动,文章基本都删掉了0.0
辣么文艺的文章还是恢复回来吧。。。
我一般这么写(当然是跟着别人学的):
#define debug(x) cerr<<#x<<'='<<x<<'\n'
学长我可以转载嘛?
可以的