在C++中将变量名转换为字符串

57

我希望将一些数据输出到文件中。例如,假设我有两个双精度向量:

vector<double> data1(10);
vector<double> data2(10); 

有没有简单的方法可以将这个输出到文件中,使第一行包含标题'data1'和'data2',后面是实际内容。输出数据的函数将传递不同的数组,因此无法硬编码标题名称 - 理想情况下,我想将变量名转换为某个字符串,然后输出该字符串,后面紧跟着向量数组的内容。但是,我不知道如何将变量名“data1”转换为字符串,或者它是否可以轻松完成(从阅读论坛的结果来看,我的猜测是不能)。如果这不可能,则另一种选择可能是使用关联容器,例如map或更简单的'pair'容器。

pair<vector<double>,string> data1(10,'data1');  

欢迎提出任何建议!


我不得不想知道你试图实现什么。如果是任意数量的数据,给每个部分命名并没有什么好处,因为无论如何都必须手动完成。 你可能正在寻找的是第二种解决方案。 - data
哇,这有点棘手,你可以尝试创建具有字符串“名称”元素的类或结构体。 - user1478209
相关内容:https://dev59.com/gXVC5IYBdhLWcg3wtzut - Ciro Santilli OurBigBook.com
8个回答

80

你可以使用预处理器中的 "stringify" # 来实现你想要的功能:

#include <stdio.h>

#define PRINTER(name) printer(#name, (name))

void printer(char *name, int value) {
    printf("name: %s\tvalue: %d\n", name, value);
}

int main (int argc, char* argv[]) {
    int foo = 0;
    int bar = 1;

    PRINTER(foo);
    PRINTER(bar);

    return 0;
}


name: foo   value: 0
name: bar   value: 1

(对不起我不太会用 <iostream>,所以用了printf。但这应该足够了。)


不错。在我看来,printf很好,只是另一种输出选项。对我来说,它们都是一样的。 - cs1349459
在像这样的小玩具中,是的,C标准库与C++ iostreams之间并没有太大的区别。然而,在更大的项目中,C ++ iostream与C标准IO同步所需的时间通常足以禁用它。在这种情况下混合使用stdio和iostreams可能会导致意外的行为。我仍然不太了解iostream :) 更多信息请访问https://en.cppreference.com/w/cpp/io/ios_base/sync_with_stdio。 - sarnold

24

试试这个:

#define GET_VARIABLE_NAME(Variable) (#Variable)

// 在函数中

int var=0;    
char* var_name= GET_VARIABLE_NAME(var);

7

我曾经遇到过同样的问题。经过一番试验,我创建了以下宏,将变量、字段、函数、方法和类型的名称转换为字符串。

#define MACRO_VARIABLE_TO_STRING(Variable) (void(Variable),#Variable)

#define MACRO_FUNCTION_TO_STRING(Function) (void(&Function),#Function)

#define MACRO_METHOD_TO_STRING(ClassName,Method) (void(&ClassName::Method),#Method)

#define MACRO_TYPE_TO_STRING(Type) (void(sizeof(Type)),#Type)

该代码使用逗号运算符和void转换来强制编译器检查变量、函数等是否真正存在。好处是它与未初始化的变量也很好地配合使用。我在VC和GCC上测试了它,使用了我发现的所有严格选项,没有任何警告信息。
int GetAndPrintValue(const char* VariableName)
{
   std::cout << VariableName << std::endl;
   return 10;
}

int Variable=GetAndPrintValue(MACRO_VARIABLE_TO_STRING(Variable));

当我编写从输入流中读取数据的解析器时,我会使用以下代码:如果解析的变量超出范围,则抛出异常,并列出未通过有效性检查的变量名称。


4
略微修改自@sarnold的答案,适用于C++:
#define DEBUG(x) std::cout << #x << " = " << x << std::endl;

一个使用此功能的示例程序:
int main() {
    int foo = 1;
    DEBUG(foo);

    return 0;
}

3
您可以使用预处理器,有一个stringify令牌,但它仅适用于源代码,而不是函数(您将获得参数名称)。

2

我有一个类似的问题。在Qt中,当我写入qDebug()时,我厌倦了不断地手动输入变量名作为字符串并且没有自动完成功能。

经过多次尝试使用不同的宏和函数后,我发现这个宏非常好用:

#define PRINT(x) ", " << #x << ": " << x

示例用法:

int someVariable = 42;
double anotherVariable = 13.37;
qDebug().nospace() << "Some text" << PRINT(someVariable) << PRINT(anotherVariable);

输出:

Some text, someVariable: 42, anotherVariable: 13.37

我猜这个(或者非常相似的东西)对于 std::cout 也会起作用。

虽然有点晚了,但我希望这能帮助到任何需要的人!


1
对于这种情况,我已经制作了一个nameof()宏。它返回变量、类型或成员的std::string名称。它的工作方式类似于C#中的nameof()。
例如:
#include "nameof.h"

std::vector<double> data1(10);
std::string name = nameof(data1); // "data1"

struct Foo1
{
    struct Foo2
    {
        Foo1* foo1;
    };

    Foo1* foo1;
    Foo2 foo2;
};

name = nameof(Foo1::foo1->foo2.foo1); // "foo1"

name = nameof(123); // std::logic_error exception

1
我认为显而易见的答案是使执行输出的函数接受标题文本作为字符串参数。

理想情况下,我希望能够调用输出函数而不需要包含变量名称的字符串参数。 - Wawel100

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接