探索 C++ Insights: 理解编译器背后的 C++ 实现

news2025/1/15 20:37:08

C++ Insights 是什么?

C++ Insights 是一款强大的工具, 专注于揭示 C++ 代码在编译器内部的实现细节. 它能够帮助开发者深入理解模板展开, 隐式类型转换, 协程等特性背后的底层机制, 是学习和教学现代 C++ 的绝佳利器.

C++ Insights 如何工作

  • Clang Based Tool: C++ Insights 基于 Clang 编译器的前端实现, 利用 Clang 提供的抽象语法树(AST)进行转换. 它通过 Clang 的强大能力, 解析和处理 C++ 代码.
  • 使用最新版的 Clang: C++ Insights 始终与 Clang 的最新稳定版本保持同步, 这意味着它能够解析和支持 C++ 的最新标准特性(如 C++20 和 C++23).
  • 不带优化的版本: C++ Insights 不进行任何优化, 仅展示编译器前端的行为. 这意味着它生成的代码完全忠实于输入代码的原始逻辑, 而不会引入优化阶段的复杂性.

C++ Insights 可以做什么

C++ Insights 的主要功能包括:

  1. 模板展开: 展示模板实例化的结果.
  2. 语法糖的展开: 将简化的语法转换为更基础的实现形式, 例如范围循环和 Lambda 表达式.
  3. 隐式行为显式化: 揭示默认构造函数, 隐式类型转换等编译器自动生成的代码.
  4. 协程展开: 展示协程在编译器中的分解过程.
  5. 内存对齐与填充: 通过展示结构体的填充字节, 优化内存布局.
  6. 生命周期可视化: 显示临时对象的创建和销毁时机.
  7. 类与继承的细节: 展示类的虚表布局. 展开继承关系和多态的实现细节.

这些功能为开发者提供了一个 “窥探编译器” 的窗口, 让许多编译器隐式的行为变得透明. 下面将为大家一一介绍.

1. 模板展开

下面的代码展示了 C++如何处理模板代码:

template <typename T>
T add(T a, T b) {
  return a + b;
}

int main() {
  add(1,2);
}

C++ Insight 输出:

template<typename T>
T add(T a, T b)
{
  return a + b;
}

/* First instantiated from: insights.cpp:7 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
int add<int>(int a, int b)
{
  return a + b;
}
#endif


int main()
{
  add(1, 2);
  return 0;
}

2. 隐式类型转换

C++ Insights 展示隐式类型转换的行为. 例如:

int main() {
    int a = 3.14;  // 隐式转换 double -> int
    return 0;
}

C++ Insight 输出:

int main()
{
  int a = static_cast<int>(3.1400000000000001);
  return 0;
}

3. 类型推导

展示 auto 的具体类型, 相对而言比较简单直白.

int main() {
    auto i = 42; // 推导为int
    auto s = "Hello"; // 推导为 const char*
    auto d = 3.14; // 推导为double
    return 0;
}

C++ Insight 输出:

int main()
{
  int i = 42;
  const char * s = "Hello";
  double d = 3.1400000000000001;
  return 0;
}

4. 默认参数

函数的默认参数会在调用点被注入:

#include <string>

void func(int x = 10) {}

void bar(std::string s = "my default string") {}

int main() {
  func();  // 使用默认参数
  bar();   // 使用默认参数
  bar();   // 使用默认参数
  return 0;
}

C++ Insight 输出:

注意此时函数funcbar没有默认参数

#include <string>

void func(int x)
{
}

void bar(std::basic_string<char, std::char_traits<char>, std::allocator<char> > s)
{
}

int main()
{
  func(10);
  bar(std::basic_string<char, std::char_traits<char>, std::allocator<char> >("my default string", std::allocator<char>()));
  bar(std::basic_string<char, std::char_traits<char>, std::allocator<char> >("my default string", std::allocator<char>()));
  return 0;
}

5. 条件编译

constexpr if 分解为编译期可选分支:

#include <iostream>

template <typename T>
void choose(T a) {
  if constexpr (std::is_integral_v<T>) {
    std::cout << "integer \n";
  } else {
    std::cout << "other type\n";
  }
}

int main() {
  choose(0);
  choose("hello");
  return 0;
}

C++ Insight 输出:

#include <iostream>

template<typename T>
void choose(T a)
{
  if constexpr(std::is_integral_v<T>) {
    std::operator<<(std::cout, "integer \n");
  } else /* constexpr */ {
    std::operator<<(std::cout, "other type\n");
  }

}

/* First instantiated from: insights.cpp:13 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
void choose<int>(int a)
{
  if constexpr(true) {
    std::operator<<(std::cout, "integer \n");
  } else /* constexpr */ {
  }

}
#endif


/* First instantiated from: insights.cpp:14 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
void choose<const char *>(const char * a)
{
  if constexpr(false) {
  } else /* constexpr */ {
    std::operator<<(std::cout, "other type\n");
  }

}
#endif


int main()
{
  choose(0);
  choose("hello");
  return 0;
}

6. 结构体 padding

struct Data {
  int i = 0;
  char c = 0;
  float f = 0;
};

C++ Insight 输出:

struct Data  /* size: 12, align: 4 */
{
  int i = 0;                      /* offset: 0, size: 4 */
  char c = 0;                     /* offset: 4, size: 1
  char __padding[3];                            size: 3 */
  float f = 0;                    /* offset: 8, size: 4 */
};

7. 范围循环

#include <vector>

int main() {
  std::vector<int> nums{1, 2, 3};
  for (auto& n : nums) {
  }
}

C++ Insight 输出:

#include <vector>

int main()
{
  std::vector<int, std::allocator<int> > nums = std::vector<int, std::allocator<int> >{std::initializer_list<int>{1, 2, 3}};
  {
    std::vector<int, std::allocator<int> > & __range1 = nums;
    std::__wrap_iter<int *> __begin1 = __range1.begin();
    std::__wrap_iter<int *> __end1 = __range1.end();
    for(; std::operator!=(__begin1, __end1); __begin1.operator++()) {
      int & n = __begin1.operator*();
    }

  }
  return 0;
}

8. Lambda 表达式

auto lambda = [](int x) { return x * 2; };

C++ Insight 输出:

class __lambda_1_15
{
  public:
  inline /*constexpr */ int operator()(int x) const
  {
    return x * 2;
  }

  using retType_1_15 = int (*)(int);
  inline constexpr operator retType_1_15 () const noexcept
  {
    return __invoke;
  };

  private:
  static inline /*constexpr */ int __invoke(int x)
  {
    return __lambda_1_15{}.operator()(x);
  }


  public:
  // /*constexpr */ __lambda_1_15() = default;

};

__lambda_1_15 lambda = __lambda_1_15{};

9. 主函数默认返回值

int main() {}

C++ Insight 输出:

int main()
{
  return 0;
}

10. 对象生命周期

可视化临时对象的创建和销毁:

#include <iostream>
#include <vector>

struct Bucket {
  std::vector<std::vector<int>> v;
};

Bucket createBucket() {
  return Bucket{{
      {1, 2, 3},
      {4, 5, 6},
  }};
}

int main() {
  for (auto vec : createBucket().v) {
    for (auto e : vec) {
      std::cout << e << ", ";
    }
    std::cout << "\n";
  }
  for (auto e : createBucket().v[0]) {
    std::cout << e << ',';
  }
  return 0;
}

C++ Insight 输出:

/*************************************************************************************
 * NOTE: This an educational hand-rolled transformation. Things can be incorrect or  *
 * buggy.                                                                            *
 *************************************************************************************/
#include <iostream>
#include <vector>

struct Bucket
{
  std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > v;
  // inline constexpr ~Bucket() noexcept = default;
};


Bucket createBucket()
{
  const int __temporary10_15[3] = {1, 2, 3};
  const int __temporary11_15[3] = {4, 5, 6};
  const std::vector<int, std::allocator<int> > __temporary12_3[2] = {std::vector<int, std::allocator<int> >{std::initializer_list<int>{__temporary10_15, 3}}, std::vector<int, std::allocator<int> >{std::initializer_list<int>{__temporary11_15, 3}}};
  return Bucket{std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >{std::initializer_list<std::vector<int, std::allocator<int> > >{__temporary12_3, 2}}};
  __temporary12_3[0].~vector();
  __temporary12_3[1].~vector();
  /* __temporary11_15 // lifetime ends here */
  /* __temporary10_15 // lifetime ends here */
  ;
}

int main()
{
  {
    Bucket __temporary16_32 = createBucket();
    std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > && __range1 = static_cast<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > &&>(__temporary16_32.v);
    std::__wrap_iter<std::vector<int, std::allocator<int> > *> __begin1 = __range1.begin();
    std::__wrap_iter<std::vector<int, std::allocator<int> > *> __end1 = __range1.end();
    for(; std::operator!=(__begin1, __end1); __begin1.operator++()) {
      std::vector<int, std::allocator<int> > vec = std::vector<int, std::allocator<int> >(__begin1.operator*());
      {
        std::vector<int, std::allocator<int> > & __range2 = vec;
        std::__wrap_iter<int *> __begin2 = __range2.begin();
        std::__wrap_iter<int *> __end2 = __range2.end();
        for(; std::operator!=(__begin2, __end2); __begin2.operator++()) {
          int e = __begin2.operator*();
          std::operator<<(std::cout.operator<<(e), ", ");
          /* e // lifetime ends here */
        }

        /* __end2 // lifetime ends here */
        /* __begin2 // lifetime ends here */
        /* __range2 // lifetime ends here */
      }
      std::operator<<(std::cout, "\n");
      vec.~vector();
    }

    /* __end1 // lifetime ends here */
    /* __begin1 // lifetime ends here */
    __temporary16_32.~Bucket();
  }
  {
    Bucket __temporary22_30 = createBucket();
    std::vector<int, std::allocator<int> > & __range1 = __temporary22_30.v.operator[](0);
    __temporary22_30.~Bucket();
    std::__wrap_iter<int *> __begin1 = __range1.begin();
    std::__wrap_iter<int *> __end1 = __range1.end();
    for(; std::operator!=(__begin1, __end1); __begin1.operator++()) {
      int e = __begin1.operator*();
      std::operator<<(std::cout.operator<<(e), ',');
      /* e // lifetime ends here */
    }

    /* __end1 // lifetime ends here */
    /* __begin1 // lifetime ends here */
    /* __range1 // lifetime ends here */
  }
  return 0;
}

11. 虚函数表

#include <iostream>

class Base {
 public:
  virtual void call() { std::cout << "base called\n"; }
  virtual ~Base() = default;
};

class Derived : public Base {
 public:
  void call() override { std::cout << "derived called\n"; }
};

int main() {
  Base* p = nullptr;
  Derived d;
  p = &d;

  p->call();
}

C++ Insight 输出:

/*************************************************************************************
 * NOTE: This an educational hand-rolled transformation. Things can be incorrect or  *
 * buggy.                                                                            *
 *************************************************************************************/
#include <stddef.h> // NULL and more
void __cxa_start(void);
void __cxa_atexit(void);
typedef int (*__vptp)();

struct __mptr
{
    short  d;
    short  i;
    __vptp f;
};

extern struct __mptr* __vtbl_array[];


#include <iostream>

typedef struct Base
{
  __mptr * __vptrBase;
} Base;

inline void callBase(Base * __this)
{
  std::operatorLessLess(&std::cout, "base called\n");
}

inline void Destructor_Base(Base * __this)
{
}

inline Base * operatorEqual(Base * __this, const Base * __rhs)
{
  return __this;
}

inline Base * Constructor_Base(Base * __this)
{
  __this->__vptrBase = __vtbl_array[0];
  return __this;
}


typedef struct Derived
{
  __mptr * __vptrBase;
} Derived;

inline void callDerived(Derived * __this)
{
  std::operatorLessLess(&std::cout, "derived called\n");
}

inline Derived * operatorEqual(Derived * __this, const Derived * __rhs)
{
  operatorEqual((Base *)__this, (Base *)__rhs);
  return __this;
}

inline Derived * operatorEqual(Derived * __this, Derived * __rhs)
{
  operatorEqual((Base *)__this, (Base *)__rhs);
  return __this;
}

inline void Destructor_Derived(Derived * __this)
{
  Destructor_Base((Base *)__this);
}

inline Derived * Constructor_Derived(Derived * __this)
{
  Constructor_Base((Base *)__this);
  __this->__vptrBase = __vtbl_array[1];
  return __this;
}


int __main(void)
{
  Base * p = NULL;
  Derived d;
  Constructor_Derived((Derived *)&d);
  p = (Base *)&d;
  (*((void (*)(Base *))((p)->__vptrBase[0]).f))((((Base *)(char *)(p)) + ((p)->__vptrBase[0]).d));
  return 0;
  /* d // lifetime ends here */
}

int main(void)
{
  __cxa_start();
  int ret = __main();
  __cxa_atexit();
  return ret;
  /* ret // lifetime ends here */
}

__mptr __vtbl_Base[2] = {{0, 0, (__vptp)callBase}, {0, 0, (__vptp)Destructor_Base}};
__mptr __vtbl_Derived[2] = {{0, 0, (__vptp)callDerived}, {0, 0, (__vptp)Destructor_Derived}};

__mptr * __vtbl_array[2] = {__vtbl_Base, __vtbl_Derived};

void __cxa_start(void)
{
}

void __cxa_atexit(void)
{
}

小结

C++ Insights 是一个揭示 C++ 编译器行为的工具, 帮助开发者理解现代 C++ 特性和底层机制. 如果你希望深入理解 C++, C++ Insights 无疑是一个值得尝试的工具!

资源链接

  • C++ Insights
  • C++ Insights: Peek behind the curtains of your C++ compiler - Andreas Fertig

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2277172.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python-leetcode-矩阵置零

73. 矩阵置零 - 力扣&#xff08;LeetCode&#xff09; class Solution:def setZeroes(self, matrix: List[List[int]]) -> None:"""Do not return anything, modify matrix in-place instead."""m, n len(matrix), len(matrix[0])row_zero …

MySQL数据库(SQL分类)

SQL分类 分类全称解释DDLData Definition Language数据定义语言&#xff0c;用来定义数据库对象&#xff08;数据库&#xff0c;表&#xff0c;字段&#xff09;DMLData Manipulation Language数据操作语言&#xff0c;用来对数据库表中的数据进行增删改DQLData Query Languag…

计算机网络 笔记 网络层1

网络层功能概述 主要的任务是把分组从源端传输到目的端&#xff0c;为分组交换网上的不同主句提供通信服务&#xff0c;网络层的传输单位是数据报。 主要的功能&#xff1b; 1&#xff0c;路由选择&#xff1a;路由选择指网络层根据特定算法&#xff0c;为数据包从源节点到目…

MyBatis-什么是MyBatis?以及MyBatis的快速入门。

简介 什么是 MyBatis&#xff1f; 什么是MyBatis? MyBatis是一款优秀的 持久层 框架&#xff0c;用于简化JDBC的开发。&#xff08;框架&#xff1a;是一个半成品软件&#xff0c;是一套可重用的、通用的、软件基础代码模型。在框架的基础上进行软件开发更加高效、规范、通用、…

Linux Kernel 之十 详解 PREEMPT_RT、Xenomai 的架构、源码、构建及使用

概述 现在的 RTOS 基本可以分为 Linux 阵营和非 Linux 阵营这两大阵营。非 Linux 阵营的各大 RTOS 都是独立发展,使用上也相对独立;而 Linux 阵营则有多种不同的实现方法来改造 Linux 以实现实时性要求。本文我们重点关注 Linux 阵营的实时内核实现方法! 本文我们重点关注 …

Swift 趣味开发:查找拼音首字母全部相同的 4 字成语(上)

概述 Swift 语言是一门现代化、安全、强大且还算性感的语言。在去年 WWDC 24 中苹果正式推出了秃头码农们期待许久的 Swift 6.0&#xff0c;它进一步完善了 Swift 语言的语法和语义&#xff0c;并再接再厉——强化了现代化并发模型的安全性和灵活性。 这里我们不妨用 Swift 来…

docker一张图理解

1、push 将本地的镜像上传到镜像仓库,要先登陆到镜像仓库。参数说明&#xff1a; –disable-content-trust : 忽略镜像的校验,默认开启 # 上传本地镜像myapache:v1到镜像仓库中。 docker push myapache:v1 1.2、search 从Docker Hub查找镜像。参数说明&#xff1a; –…

IoTDB 常见问题 QA 第三期

关于 IoTDB 的 Q & A IoTDB Q&A 第三期持续更新&#xff01;我们将定期汇总我们将定期汇总社区讨论频繁的问题&#xff0c;并展开进行详细回答&#xff0c;通过积累常见问题“小百科”&#xff0c;方便大家使用 IoTDB。 Q1&#xff1a;查询最新值 & null 数据相加方…

MyBatis实现数据库的CRUD

本文主要讲解使用MyBatis框架快速实现数据库中最常用的操作——CRUD。本文讲解的SQL语句都是MyBatis基于注解的方式定义的&#xff0c;相对简单。 Mybatis中#占位符和$拼接符的区别 “#”占位符 在使用MyBatis操作数据库的时候&#xff0c;可以直接使用如下SQL语句删除一条数…

Spring Boot 下的Swagger 3.0 与 Swagger 2.0 的详细对比

先说结论&#xff1a; Swgger 3.0 与Swagger 2.0 区别很大&#xff0c;Swagger3.0用了最新的注释实现更强大的功能&#xff0c;同时使得代码更优雅。 就个人而言&#xff0c;如果新项目推荐使用Swgger 3.0&#xff0c;对于工具而言新的一定比旧的好&#xff1b;对接于旧项目原…

关于2025年智能化招聘管理系统平台发展趋势

2025年&#xff0c;招聘管理领域正站在变革的十字路口&#xff0c;全新的技术浪潮与不断变化的职场生态相互碰撞&#xff0c;促使招聘管理系统成为重塑企业人才战略的关键力量。智能化招聘管理系统平台在这一背景下迅速崛起&#xff0c;其发展趋势不仅影响企业的招聘效率与质量…

go语言的sdk 适合用go原生还是gozero框架开发的判断与总结

在决定是否使用 Go 原生&#xff08;纯 Go&#xff09;开发&#xff0c;还是使用 GoZero 框架开发时&#xff0c;主要取决于项目的需求、规模和开发的复杂性。GoZero 框架提供了一些额外的功能&#xff0c;如微服务架构、RPC 支持、API 网关、任务调度等&#xff0c;这些是基于…

Elasticsearch 批量导入数据(_bluk方法)

官方API&#xff1a;https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html 建议先看API POST /<索引名>/_bulk 格式要求&#xff1a; POST _bulk { "index" : { "_index" : "test", "_id" : &q…

Mysql--重点篇--索引(索引分类,Hash和B-tree索引,聚簇和非聚簇索引,回表查询,覆盖索引,索引工作原理,索引失效,索引创建原则等)

索引是数据库中用于加速查询操作的重要机制。通过索引&#xff0c;MySQL可以快速定位到满足查询条件的数据行&#xff0c;而不需要扫描整个表。合理的索引设计可以显著提高查询性能&#xff0c;但不合理的索引可能会导致性能下降和磁盘空间浪费。因此&#xff0c;理解索引的工作…

mybatis-spring @MapperScan走读分析

接上一篇文章&#xff1a;https://blog.csdn.net/qq_26437925/article/details/145100531&#xff0c; 本文注解分析mybatis-spring中的MapperScan注解&#xff0c;则将容易许多。 目录 MapperScan注解定义ConfigurationClassPostProcessor扫描注册beanDefinitionorg.mybatis.s…

【STM32】HAL库USB实现软件升级DFU的功能操作及配置

【STM32】HAL库USB实现软件升级DFU的功能操作及配置 文章目录 DFUHAL库的DFU配置修改代码添加条件判断和跳转代码段DFU烧录附录&#xff1a;Cortex-M架构的SysTick系统定时器精准延时和MCU位带操作SysTick系统定时器精准延时延时函数阻塞延时非阻塞延时 位带操作位带代码位带宏…

计算机视觉算法实战——实时车辆检测和分类(主页有相关源码)

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​ ​​​​​​​​​​​​​​​​​​ 1. 领域介绍✨✨ 实时车辆检测和分类是计算机视觉中的一个重要应用领域&#xff0c;旨在从视频流或…

机器学习(1):线性回归概念

1 线性回归基础 1.1 什么是线性 例如&#xff1a;汽车每小时60KM&#xff0c;3小时可以行使多长距离&#xff1f;已知汽车的速度&#xff0c;则汽车的行使距离只与时间唯一相关。在二元的直角坐标系中&#xff0c;描出这一关系的图是一条直线&#xff0c;所以称为线性关系。 线…

ThinkPHP 8的一对一关联

【图书介绍】《ThinkPHP 8高效构建Web应用》-CSDN博客 《2025新书 ThinkPHP 8高效构建Web应用 编程与应用开发丛书 夏磊 清华大学出版社教材书籍 9787302678236 ThinkPHP 8高效构建Web应用》【摘要 书评 试读】- 京东图书 使用VS Code开发ThinkPHP项目-CSDN博客 编程与应用开…

探索图像编辑的无限可能——Adobe Photoshop全解析

文章目录 前言一、PS的历史二、PS的应用场景三、PS的功能及工具用法四、图层的概念五、调整与滤镜六、创建蒙版七、绘制形状与路径八、实战练习结语 前言 在当今数字化的世界里&#xff0c;视觉内容无处不在&#xff0c;而创建和编辑这些内容的能力已经成为许多行业的核心技能…