Replacement for _Stdlib_Getdemangledtypename() in Swift 2.2

How do I print the type or class of a variable in Swift?

Update September 2016

Swift 3.0: Use type(of:), e.g. type(of: someThing) (since the dynamicType keyword has been removed)

Update October 2015:

I updated the examples below to the new Swift 2.0 syntax (e.g. println was replaced with print, toString() is now String()).

From the Xcode 6.3 release notes:

@nschum points out in the comments that the Xcode 6.3 release notes show another way:

Type values now print as the full demangled type name when used with
println or string interpolation.

import Foundation

class PureSwiftClass { }

var myvar0 = NSString() // Objective-C class
var myvar1 = PureSwiftClass()
var myvar2 = 42
var myvar3 = "Hans"

print( "String(myvar0.dynamicType) -> \(myvar0.dynamicType)")
print( "String(myvar1.dynamicType) -> \(myvar1.dynamicType)")
print( "String(myvar2.dynamicType) -> \(myvar2.dynamicType)")
print( "String(myvar3.dynamicType) -> \(myvar3.dynamicType)")

print( "String(Int.self) -> \(Int.self)")
print( "String((Int?).self -> \((Int?).self)")
print( "String(NSString.self) -> \(NSString.self)")
print( "String(Array<String>.self) -> \(Array<String>.self)")

Which outputs:

String(myvar0.dynamicType) -> __NSCFConstantString
String(myvar1.dynamicType) -> PureSwiftClass
String(myvar2.dynamicType) -> Int
String(myvar3.dynamicType) -> String
String(Int.self) -> Int
String((Int?).self -> Optional<Int>
String(NSString.self) -> NSString
String(Array<String>.self) -> Array<String>

Update for Xcode 6.3:

You can use the _stdlib_getDemangledTypeName():

print( "TypeName0 = \(_stdlib_getDemangledTypeName(myvar0))")
print( "TypeName1 = \(_stdlib_getDemangledTypeName(myvar1))")
print( "TypeName2 = \(_stdlib_getDemangledTypeName(myvar2))")
print( "TypeName3 = \(_stdlib_getDemangledTypeName(myvar3))")

and get this as output:

TypeName0 = NSString
TypeName1 = __lldb_expr_26.PureSwiftClass
TypeName2 = Swift.Int
TypeName3 = Swift.String

Original answer:

Prior to Xcode 6.3 _stdlib_getTypeName got the mangled type name of a variable. Ewan Swick's blog entry helps to decipher these strings:

e.g. _TtSi stands for Swift's internal Int type.

Mike Ash has a great blog entry covering the same topic.

Unmangling the result of std::type_info::name

Given the attention this question / answer receives, and the valuable feedback from GManNickG, I have cleaned up the code a little bit. Two versions are given: one with C++11 features and another one with only C++98 features.

In file type.hpp

#ifndef TYPE_HPP
#define TYPE_HPP

#include <string>
#include <typeinfo>

std::string demangle(const char* name);

template <class T>
std::string type(const T& t) {

return demangle(typeid(t).name());
}

#endif

In file type.cpp (requires C++11)

#include "type.hpp"
#ifdef __GNUG__
#include <cstdlib>
#include <memory>
#include <cxxabi.h>

std::string demangle(const char* name) {

int status = -4; // some arbitrary value to eliminate the compiler warning

// enable c++11 by passing the flag -std=c++11 to g++
std::unique_ptr<char, void(*)(void*)> res {
abi::__cxa_demangle(name, NULL, NULL, &status),
std::free
};

return (status==0) ? res.get() : name ;
}

#else

// does nothing if not g++
std::string demangle(const char* name) {
return name;
}

#endif

Usage:

#include <iostream>
#include "type.hpp"

struct Base { virtual ~Base() {} };

struct Derived : public Base { };

int main() {

Base* ptr_base = new Derived(); // Please use smart pointers in YOUR code!

std::cout << "Type of ptr_base: " << type(ptr_base) << std::endl;

std::cout << "Type of pointee: " << type(*ptr_base) << std::endl;

delete ptr_base;
}

It prints:

Type of ptr_base: Base*
Type of pointee: Derived

Tested with g++ 4.7.2, g++ 4.9.0 20140302 (experimental), clang++ 3.4 (trunk 184647), clang 3.5 (trunk 202594) on Linux 64 bit and g++ 4.7.2 (Mingw32, Win32 XP SP2).

If you cannot use C++11 features, here is how it can be done in C++98, the file type.cpp is now:

#include "type.hpp"
#ifdef __GNUG__
#include <cstdlib>
#include <memory>
#include <cxxabi.h>

struct handle {
char* p;
handle(char* ptr) : p(ptr) { }
~handle() { std::free(p); }
};

std::string demangle(const char* name) {

int status = -4; // some arbitrary value to eliminate the compiler warning

handle result( abi::__cxa_demangle(name, NULL, NULL, &status) );

return (status==0) ? result.p : name ;
}

#else

// does nothing if not g++
std::string demangle(const char* name) {
return name;
}

#endif


(Update from Sep 8, 2013)

The accepted answer (as of Sep 7, 2013), when the call to abi::__cxa_demangle() is successful, returns a pointer to a local, stack allocated array... ouch!

Also note that if you provide a buffer, abi::__cxa_demangle() assumes it to be allocated on the heap. Allocating the buffer on the stack is a bug (from the gnu doc): "If output_buffer is not long enough, it is expanded using realloc." Calling realloc() on a pointer to the stack... ouch! (See also Igor Skochinsky's kind comment.)

You can easily verify both of these bugs: just reduce the buffer size in the accepted answer (as of Sep 7, 2013) from 1024 to something smaller, for example 16, and give it something with a name not longer than 15 (so realloc() is not called). Still, depending on your system and the compiler optimizations, the output will be: garbage / nothing / program crash.

To verify the second bug: set the buffer size to 1 and call it with something whose name is longer than 1 character. When you run it, the program almost assuredly crashes as it attempts to call realloc() with a pointer to the stack.


(The old answer from Dec 27, 2010)

Important changes made to KeithB's code: the buffer has to be either allocated by malloc or specified as NULL. Do NOT allocate it on the stack.

It's wise to check that status as well.

I failed to find HAVE_CXA_DEMANGLE. I check __GNUG__ although that does not guarantee that the code will even compile. Anyone has a better idea?

#include <cxxabi.h>

const string demangle(const char* name) {

int status = -4;

char* res = abi::__cxa_demangle(name, NULL, NULL, &status);

const char* const demangled_name = (status==0)?res:name;

string ret_val(demangled_name);

free(res);

return ret_val;
}


Related Topics



Leave a reply



Submit