เมื่อได้รับความสนใจจากคำถาม / คำตอบนี้และข้อเสนอแนะที่มีค่าจากGManNickGฉันได้ทำความสะอาดโค้ดเล็กน้อยแล้ว มีให้สองเวอร์ชัน: เวอร์ชันหนึ่งที่มีคุณสมบัติ C ++ 11 และอีกเวอร์ชันหนึ่งมีคุณสมบัติ C ++ 98 เท่านั้น
ในไฟล์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
ในไฟล์type.cpp (ต้องใช้ C ++ 11)
#include "type.hpp"
#ifdef __GNUG__
#include <cstdlib>
#include <memory>
#include <cxxabi.h>
std::string demangle(const char* name) {
int status = -4;
std::unique_ptr<char, void(*)(void*)> res {
abi::__cxa_demangle(name, NULL, NULL, &status),
std::free
};
return (status==0) ? res.get() : name ;
}
#else
std::string demangle(const char* name) {
return name;
}
#endif
การใช้งาน:
#include <iostream>
#include "type.hpp"
struct Base { virtual ~Base() {} };
struct Derived : public Base { };
int main() {
Base* ptr_base = new Derived();
std::cout << "Type of ptr_base: " << type(ptr_base) << std::endl;
std::cout << "Type of pointee: " << type(*ptr_base) << std::endl;
delete ptr_base;
}
มันพิมพ์:
ประเภทของ ptr_base: Base*
ประเภทของพอยน์ตี้:Derived
ทดสอบด้วย g ++ 4.7.2, g ++ 4.9.0 20140302 (ทดลอง), clang ++ 3.4 (trunk 184647), clang 3.5 (trunk 202594) บน Linux 64 บิตและ g ++ 4.7.2 (Mingw32, Win32 XP SP2)
หากคุณไม่สามารถใช้คุณสมบัติ C ++ 11 ได้นี่คือวิธีที่สามารถทำได้ใน C ++ 98 ตอนนี้ไฟล์type.cppคือ:
#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;
handle result( abi::__cxa_demangle(name, NULL, NULL, &status) );
return (status==0) ? result.p : name ;
}
#else
std::string demangle(const char* name) {
return name;
}
#endif
(อัปเดตเมื่อวันที่ 8 ก.ย. 2556)
คำตอบที่ได้รับการยอมรับ (ณ วันที่ 7 กันยายน 2556)เมื่อการโทรabi::__cxa_demangle()
สำเร็จจะส่งกลับตัวชี้ไปยังอาร์เรย์ที่จัดสรรแบบสแต็กภายในเครื่อง ... อุ๊ย!
โปรดทราบว่าหากคุณจัดเตรียมบัฟเฟอร์ให้abi::__cxa_demangle()
ถือว่าบัฟเฟอร์ถูกจัดสรรบนฮีป การจัดสรรบัฟเฟอร์บนสแต็กเป็นจุดบกพร่อง (จากเอกสาร gnu): "ถ้าoutput_buffer
ไม่ยาวพอจะขยายโดยใช้realloc
" เรียกrealloc()
ตัวชี้ไปที่กอง ... อุ๊ย! (ดูความคิดเห็นของIgor Skochinskyด้วย)
คุณสามารถตรวจสอบข้อบกพร่องทั้งสองนี้ได้อย่างง่ายดาย: เพียงแค่ลดขนาดบัฟเฟอร์ในคำตอบที่ยอมรับ (ณ วันที่ 7 กันยายน 2013) จาก 1024 เป็นขนาดที่เล็กกว่าเช่น 16 และตั้งชื่อที่มีความยาวไม่เกิน 15 (ดังนั้นrealloc()
คือไม่เรียก) อย่างไรก็ตามขึ้นอยู่กับระบบของคุณและการปรับแต่งคอมไพลเลอร์ผลลัพธ์จะเป็น: ขยะ / ไม่มีอะไร / โปรแกรมขัดข้อง
ในการตรวจสอบข้อบกพร่องที่สอง: ตั้งค่าขนาดบัฟเฟอร์เป็น 1 และเรียกมันด้วยชื่อที่ยาวกว่า 1 อักขระ เมื่อคุณเรียกใช้โปรแกรมเกือบจะล้มเหลวอย่างแน่นอนเนื่องจากพยายามเรียกrealloc()
ด้วยตัวชี้ไปที่สแต็ก
(คำตอบเก่าเมื่อวันที่ 27 ธันวาคม 2553)
การเปลี่ยนแปลงที่สำคัญที่ทำกับรหัสของ KeithB : บัฟเฟอร์จะต้องถูกจัดสรรโดย malloc หรือระบุเป็น NULL อย่าจัดสรรไว้ในสแต็ก
ควรตรวจสอบสถานะนั้นด้วย
HAVE_CXA_DEMANGLE
ฉันยังไม่พบ ฉันตรวจสอบ__GNUG__
แม้ว่าจะไม่ได้รับประกันว่าโค้ดจะคอมไพล์ได้ ใครมีความคิดที่ดีกว่านี้
#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;
}
#include <cxxabi.h>
โปรดทราบว่าความต้องการนี้ อย่างอื่นใช้งานได้ดีขอบคุณ