在 C++ 顯示完整的 typeid 型別名稱

| | 0 Comments| 08:51
Categories:

在 C++ 裡面,如果需要知道一個型別的資訊,基本上可以使用 typeid() 這個運算子(文件)來取得 std::type_info文件)的物件、然後他還有提供 name() 這個函式,可以用來取得型別的名稱。

所以,在一般的情況下,如果要知道一個型別的名稱,可以使用下面的形式來做:

#include <iostream>
#include <tuple>
 
int main()
{
  std::cout
    << "float: " << typeid(float).name() << "\n"
    << "tuple: " << typeid(std::tuple<int, double>).name() << "\n"
    << std::endl;
}

在 Visual Studio 的話,會輸出下面的結果,非常好閱讀。

float: float
tuple: class std::tuple<int,double>

在特定的狀況下,這種資訊也是適合用來除錯、或是回報訊息給使用者的。


不過同樣的寫法如果換成是用 g++ 或 clang 的話,則是會出現下面的結果:

float: f
tuple: St5tupleIJidEE

感覺上,變得相當難以理解了?

為什麼會這樣呢?這是因為這個函式回傳的結果基本上會是實作自己定義的(implementation defined),而 g++ 和 clang 選擇的方法是回傳「mangled name」的結果。

而他的處理方法,基本上就是去簡化名稱,像是 float 就變成 fstd 變成 St 這樣;它會讓整個字串變得精簡,但是相對地也不適合人類閱讀。

而如果希望在 Linux 上可以讓結果變得像 Visual C++ 的結果一樣可以閱讀的話,可以在執行的時候搭配「c++filt」這個程式(說明)來使用。這邊比較適合的方法,是:

./a.out | c++filt -t

這樣把 ./a.out 的結果導向給 c++filt、並加上「-t」讓他去處理型別,這樣就可以得到適合人類閱讀的結果了!


不過這是在執行的時候去處理,如果想在寫在程式裡面的話要怎麼辦呢?這邊可以使用 libstdc++ 的 demangling 功能(文件)來做,但是基本上就會變程式綁死平台的了。

所以如果要考慮跨平台的話,比較好的方法,或許是使用 Boost C++ Libraries 的功能了~

要使用也算滿簡單的,只要直接呼叫 boost::core::demangle() 這個函式(文件)、讓它處理名稱就可以了。

下面就是修改過的版本:

#include <iostream>
#include <tuple>
 
#include <boost/core/demangle.hpp>
 
int main()
{
  std::cout
    << "float: " << boost::core::demangle(typeid(float).name()) << "\n"
    << "tuple: " << boost::core::demangle(typeid(std::tuple<int, double>).name()) << "\n"
    << std::endl;
}

這樣基本上就可以直接輸出人類看得懂的型別名稱了。

Leave a Reply

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *