How can I demangle names without running c++filt

if I run this like
./prog 

I get:

St13runtime_error
too few arguments


if I run this like:
./prog | c++filt -t

I get:

std::runtime_error
too few arguments


How can demangle names within my program.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<iostream>
#include<vector>
#include<typeinfo>
#include<stdexcept>

int main(int argc, char** argv) try {
    std::vector<const char*> args(argv, argv + argc);

    const char* dir = args[1];
    const char* regex = args[2];
    if(args.size() !=3) throw std::runtime_error("too few arguments");

    return 0;
}
catch (std::exception& e) {
    std::cout << typeid(e).name() << '\n';
    std::cout << e.what() << '\n';
}


Last edited on

./prog c++filt -t


no |

argc is 3
argv[0] is ./prog
argv[1] is c++filt
argv[2] is -t
Sorry maybe I wasn't clear, I want it to throw an exception. The pipe is so the program c++filt can demangle the name. What I want is too demangle the name before I send it to the terminal.
Last edited on
You're saying you want to implement the logic that c++filt does within your program itself?
Each compiler will have its own way of doing name demangling.

Are you on a Linux platform using gcc or clang? If you install the binutils-dev package, apparently you can link to a library that do the same demangling.
https://stackoverflow.com/a/4779961
On Linux you can use /usr/include/demangle.h which comes with binutils-dev package. You'll have to link to the libiberty from binutils.


Then, it looks like you can pass the mangled string into a demangle() function.

Edit:
According to https://en.wikipedia.org/wiki/Name_mangling
another alternative is to use the builtin GCC ABI:
1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
#include <stdlib.h>
#include <cxxabi.h>

int main() {
	const char *mangled_name = "_ZNK3MapI10StringName3RefI8GDScriptE10ComparatorIS0_E16DefaultAllocatorE3hasERKS0_";
	int status = -1;
	char *demangled_name = abi::__cxa_demangle(mangled_name, NULL, NULL, &status);
	printf("Demangled: %s\n", demangled_name);
	free(demangled_name);
	return 0;
}
Last edited on
This works but I was hoping for something better.

Edit this was posted before I saw the above reply
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
35
36
37
38
#include<iostream>
#include<vector>
#include<cstdio>
#include<memory>
#include<typeinfo>
#include<stdexcept>
#include<string>
#include<array>

std::string exec(const std::string cmd) {
    std::array<char, 128> buffer;
    std::string result;
    std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
    if (!pipe) {
        throw std::runtime_error("popen() failed!");
    }
    while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
        result += buffer.data();
    }
    return result;
}

std::string demangle(const std::string  mangled){
    return exec(std::string("c++filt -t ") + mangled);
}

int main(int argc, char** argv) try {
    std::vector<const char*> args(argv, argv + argc);

   throw std::runtime_error("too few arguments");

    return 0;
}
catch (std::exception& e) {
    std::cout << demangle(typeid(e).name()) << '\n';
    std::cout << e.what() << '\n';
}
Last edited on
@Ganado Thank you very much -- it is exactly what I was looking for.
Last edited on
Topic archived. No new replies allowed.