C++拾趣——转换编译器生成的类型名为代码中的类型名

18 篇文章 9 订阅

在软件开发中,特别是在使用C++这类静态类型语言时,编译器在编译过程中会生成许多内部表示,包括类型信息。这些内部类型名通常用于编译器的内部处理,比如类型检查、优化和代码生成等。
在这里插入图片描述

然而,在编写源代码或进行调试时,我们更习惯于使用人类可读和易于理解的类型名。比如我们不太能看懂_ZSt10_ConstructIN11composition6TalkerEJRN6rclcpp11NodeOptionsEEEvPT_DpOT0_,但是可以看懂void std::_Construct<composition::Talker, rclcpp::NodeOptions&>(composition::Talker*, rclcpp::NodeOptions&)

因此,将C++编译器生成的类型名转换成代码中的类型名具有多方面的必要性:

  • 提高代码的可读性。源代码中的类型名应该清晰地反映其意图和用途,以便于开发者和维护者理解。编译器生成的类型名往往包含编译器特有的前缀、后缀或编码,这使得它们难以被人类直接理解。通过转换成代码中的类型名,可以大大提高代码的可读性和可维护性。

  • 促进团队合作。在团队开发环境中,不同的开发者可能使用不同的编译器或编译器版本。如果直接使用编译器生成的类型名,可能会导致类型名在不同环境下不一致,进而增加团队合作的难度。而将类型名转换为代码中定义的类型名,可以确保所有开发者在查看和理解代码时使用的是相同的类型名,从而降低沟通成本和错误率。

  • 简化调试过程。在调试过程中,开发者经常需要查看变量的类型和值。如果变量使用的是编译器生成的类型名,那么在调试器中查找和识别这些类型可能会变得困难。而将类型名转换为代码中定义的类型名,可以使调试过程更加直观和高效。

下面我们将通过代码编写一个工具,负责将这些编译器生成的类型名转换成代码中的类型名。

代码

#include <iostream>
#include <typeinfo>
#include <cxxabi.h>
#include <memory>
#include <vector>

// 辅助函数:解码类型名
std::string demangle(const char* name) {
    int status = 0;
    char* demangled = abi::__cxa_demangle(name, nullptr, nullptr, &status);
    std::string result = (status == 0) ? demangled : name;
    free(demangled);
    return result;
}

int main(int argc, char* argv[]) {
    for (int i = 1; i < argc; ++i) {
        std::cout << "argv[" << i << "]" << std::endl << argv[i] << " -> " << demangle(argv[i]) << std::endl << std::endl;
    }
    return 0;
}

测试

我们输入《Robot Operating System——深度解析通过符号和隐式加载动态库的运行模式》一文中追踪的符号。

./build/DemangleExample _ZN11composition6TalkerC1ERKN6rclcpp11NodeOptionsE ZSt10_ConstructIN11composition6TalkerEJRN6rclcpp11NodeOptionsEEEvPT_DpOT0 ZNSt23_Sp_counted_ptr_inplaceIN11composition6TalkerESaIvELN9__gnu_cxx12_Lock_policyE2EEC1IJRN6rclcpp11NodeOptionsEEEES2_DpOT ZNSt14__shared_countILN9__gnu_cxx12_Lock_policyE2EEC1IN11composition6TalkerESaIvEJRN6rclcpp11NodeOptionsEEEERPT_St20_Sp_alloc_shared_tagIT0_EDpOT1 ZNSt12__shared_ptrIN11composition6TalkerELN9__gnu_cxx12_Lock_policyE2EEC1ISaIvEJRN6rclcpp11NodeOptionsEEEESt20_Sp_alloc_shared_tagIT_EDpOT0 ZNSt10shared_ptrIN11composition6TalkerEEC1ISaIvEJRN6rclcpp11NodeOptionsEEEESt20_Sp_alloc_shared_tagIT_EDpOT0

然后我们会看到如下结果

argv[1]
_ZN11composition6TalkerC1ERKN6rclcpp11NodeOptionsE -> composition::Talker::Talker(rclcpp::NodeOptions const&)

argv[2]
ZSt10_ConstructIN11composition6TalkerEJRN6rclcpp11NodeOptionsEEEvPT_DpOT0 -> void std::_Construct<composition::Talker, rclcpp::NodeOptions&>(composition::Talker*, rclcpp::NodeOptions&)

argv[3]
ZNSt23_Sp_counted_ptr_inplaceIN11composition6TalkerESaIvELN9__gnu_cxx12_Lock_policyE2EEC1IJRN6rclcpp11NodeOptionsEEEES2_DpOT -> std::_Sp_counted_ptr_inplace<composition::Talker, std::allocator<void>, (__gnu_cxx::_Lock_policy)2>::_Sp_counted_ptr_inplacerclcpp::NodeOptions&(std::allocator<void>, rclcpp::NodeOptions&)

argv[4]
ZNSt14__shared_countILN9__gnu_cxx12_Lock_policyE2EEC1IN11composition6TalkerESaIvEJRN6rclcpp11NodeOptionsEEEERPT_St20_Sp_alloc_shared_tagIT0_EDpOT1 -> std::__shared_count<(__gnu_cxx::_Lock_policy)2>::__shared_count<composition::Talker, std::allocator<void>, rclcpp::NodeOptions&>(composition::Talker*&, std::_Sp_alloc_shared_tag<std::allocator<void> >, rclcpp::NodeOptions&)

argv[5]
ZNSt12__shared_ptrIN11composition6TalkerELN9__gnu_cxx12_Lock_policyE2EEC1ISaIvEJRN6rclcpp11NodeOptionsEEEESt20_Sp_alloc_shared_tagIT_EDpOT0 -> std::__shared_ptr<composition::Talker, (__gnu_cxx::_Lock_policy)2>::__shared_ptr<std::allocator<void>, rclcpp::NodeOptions&>(std::_Sp_alloc_shared_tag<std::allocator<void> >, rclcpp::NodeOptions&)

argv[6]
ZNSt10shared_ptrIN11composition6TalkerEEC1ISaIvEJRN6rclcpp11NodeOptionsEEEESt20_Sp_alloc_shared_tagIT_EDpOT0 -> std::shared_ptr<composition::Talker>::shared_ptr<std::allocator<void>, rclcpp::NodeOptions&>(std::_Sp_alloc_shared_tag<std::allocator<void> >, rclcpp::NodeOptions&)

这样整个符号就容易理解了。

代码地址

https://github.com/f304646673/cpulsplus/tree/master/demangled

  • 23
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

breaksoftware

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值