开发者

generic way to print out variable name in c++

开发者 https://www.devze.com 2023-03-18 17:58 出处:网络
given a class struct { int a1; bool a2; ... char* a500; ... char a10000; } 开发者_JS百科 I want to print or stream out

given a class

struct {
  int a1;
  bool a2;
  ...
  char* a500;
  ...
  char a10000;      
}
开发者_JS百科

I want to print or stream out

"a1 value is SOME_VALUE"  
"a2 value is SOME_VALUE"
"a500 value is SOME_VALUE"
...
"a10000 value is SOME_VALUE"

the type of the member variables are not the same (mainly, int, bool, char*, etc, i.e., no need to overload << 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?

Thanks for any comments!


You can employ an evil macro:

#define DUMP(a) \
    do { std::cout << #a " is value " << (a) << std::endl; } while(false)

Usage example (Edit now updated with example for struct members):

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

See live demo on CodePad

Why the funny macro?

Answering the unasked question. Consider what happens if you nest the macro invocation in a conditional, or a for loop. Marshall Cline explains the rest


The feature you're looking for is typically called reflection. It is not part of C++, since in compiled languages the information you're after (human-readable variable names) is generally not kept by the compiler. It is not needed to run the code, so there's no point in including it.

Debuggers can often inspect either out-of-band symbol information, or symbol data kept in binaries for this very purpose, to show such names but re-doing that for this purpose is probably more work than it's worth.

I would suggest looking for some of the many "tricks" (=solutions) to implement this yourself.


The watch macro is one of the most useful tricks ever.

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

If you’re debugging your code, watch(variable); will print the name of the variable and its value. (It’s possible because it's built during preprocessing time.)


It's not possible (see the other answers).

One workaround for this is to use automatic code generation. You write the field definitions in a file and then generate the .h and .cpp files from it. I used this for a code which had around 100 classes with lots of fields. It was able to generate the code for sending them to streams (mostly debugging) and for socket communication. It's very reliable (never had to test any of those functionalities), but since it's not pure C++ it might not be the solution for you.


There is no way to enumerate members of the class in C++, since there is no reflection in C++. So you cannot have access to the variable name.

You could use pointers to members though...

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 can print structs. This script generates gdb script to set breakpoints and print values at specified by gdb_print locations:

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

0

精彩评论

暂无评论...
验证码 换一张
取 消