我正在扩展我们的内部调试库,而且我遇到了一个奇怪的问题。我想将变量名称输出为字符串。从本网站的elsewhere开始,我发现可以在文件中使用宏来执行此操作:
@Test
public void testParcel() {
Comment test = new Comment();
test.setId(testNr0Id);
test.setComment(testNr0String);
// Obtain a Parcel object and write the parcelable object to it:
Parcel parcel = Parcel.obtain();
test.writeToParcel(parcel, 0);
// After you're done with writing, you need to reset the parcel for reading:
parcel.setDataPosition(0);
// Reconstruct object from parcel and asserts:
Comment createdFromParcel = Comment.CREATOR.createFromParcel(parcel);
assertEquals(test, createdFromParcel);
}
这会输出#define VarToStr(v) #v
...
printf("%s\n", VarToStr(MatName));
。但是现在让我们通过跨文件的函数来尝试这个(Matrix是一个已定义的类型):
MatName
这会输出// DebugHelpers.h
#define VarToStr(v) #v
...
void PrintMatrix(const Matrix &InputMat)
{
printf("%s\n", VarToStr(InputMat));
... // output InputMat contents
}
// DataAnalysis.cc
#include DebugHelpers.h
...
void AnalysisSubProgram342()
{
Matrix MatName;
...
PrintMatrix(MatName);
}
,而不是InputMat
。另一个文件中的函数如何从调用文件中获取变量名?
虽然更复杂的解决方案(包装类等)对更大的社区有用,但我的实现需要尽量减少对先前存在的代码/类的影响。
更新
受到天顶评论的启发,我实施了他提出的两个解决方案,以便进行比较,并且快速完成工作。该宏适用于简单输出,而该功能允许更复杂的工作(以及类型检查/重载)。我不知道预处理器宏可能如此复杂。我记得两者都是为了将来使用。谢谢!
答案 0 :(得分:9)
你做不到。 C和C ++都不会在运行时保留变量名。
你所做的所有宏都是替换在编译时发生的文本。
答案 1 :(得分:4)
正如其他人所提到的,C ++不支持运行时反射,所以如果你想要一个字符串,其内容只能在运行时知道(即调用PrintMatrix
时),你需要将其作为参数传递。
因为你总是知道你的变量是什么'您不需要VarToStr
宏名称
// DebugHelpers.h
void PrintMatrix(const Matrix &InputMat, const char* MatName)
{
printf("%s\n", MatName);
... // output InputMat contents
}
// DataAnalysis.cc
#include DebugHelpers.h
...
void AnalysisSubProgram342()
{
Matrix MatName;
...
PrintMatrix(MatName, "MatName");
}
但是还有另一种选择:make PrintMatrix
一个宏本身,因为它无论如何只是一个调试的东西:
// DebugHelpers.h
#define PRINT_MATRIX(InputMat)\
printf(#InputMat "\n");\
... // output InputMat contents
// DataAnalysis.cc
#include DebugHelpers.h
...
void AnalysisSubProgram342()
{
Matrix MatName;
...
PRINT_MATRIX(MatName);
}
现在预处理后,AnalysisSubProgram342
将如下所示:
void AnalysisSubProgram342()
{
Matrix MatName;
...
printf("MatName\n");
... // output InputMat contents
}
答案 2 :(得分:1)
一般情况下,你不能这样做(在运行时获取变量的名称,例如从其地址或在C ++中获取它的引用)。
我专注于Linux:
但是,在Linux(和基于GNU glibc的系统)上,对于全局变量(和函数),您可以使用GNU特定的dladdr(3)函数。
如果使用-g
编译了所有相关代码(以获取调试信息),则可能会以DWARF格式解析调试信息(也许还使用__builtin_frame_address
等)。有些痛苦,您可以从call stack的地址获取一些局部变量的名称。这将是一项重大的努力(可能是几个月的工作)。 Ian Taylor的libbacktrace(GCC内部)可能是一个有用的起点。
您也可以开始(假设所有内容都使用-g
编译),例如popen(3),gdb -p
调试过程。
请注意,最近的GDB调试器可以在Python或Guile中编写脚本,因此实际上,为GDB开发Python或Guile函数会更快。
您也可以简单地添加调试输出,如here。