BianChengNan's Blog

Coding is hard, you can make it easy!


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 搜索

置顶声明

发表于 2029-03-01 | 更新于: 2024-12-21 | 分类于 原
字数统计: | 阅读时长 ≈ 分钟

实在抱歉,因为图片使用的是 http 链接,在 chrome 或者 edge 浏览器中打开本博客的时候,看不到文章中的图片。

可以在 chrome 中通过 chrome://flags (在 edge 中通过 edge://flags)启用 Insecure origins treated as secure,

并且把图床地址 http://resources.bianchengnan.tech 加入到信任列表的方式查看图片。(非常感谢群友 张帆 的提示)

整个操作如下图:

enable-show-image-in-chrome

如果还不能查看相关图片,请联系我,或者到我的公众号里查看。

我的个人微信号是 BianChengNan,公众号是 编程难。

基础知识 | 函数基础 5 —— 实战修复虚函数导致的编译错误

发表于 2024-12-01 | 更新于: 2024-12-21 | 分类于 基础知识
字数统计: | 阅读时长 ≈ 分钟

缘起

前一阵子,同事遇到了一个奇怪的编译问题,大概情况如下:

classA 是模块 A 中的一个类, classA 没有定义构造函数,其它函数都是导出的。B 模块依赖了 A 模块,并且会调用 classA 的接口。当在 B 模块中添加了实例化 classA 对象的代码的时候,报链接错误,提示找不到 classA 类的某个虚函数。

我帮忙看过之后发现又是虚函数相关的编译问题(正好最近在总结虚函数相关的问题),这是送上门的素材啊!

阅读全文 »

基础知识 | 函数基础 4 —— 又崩溃了,原来是虚函数声明顺序不一致捣的鬼

发表于 2024-11-09 | 更新于: 2024-12-21 | 分类于 基础知识
字数统计: | 阅读时长 ≈ 分钟

缘起

前一阵子,同事遇到了一个崩溃问题,解决后发现这个崩溃是由于在公共类中加了一个虚函数接口,但是并没有编译相关模块导致的。这种崩溃问题是老朋友了。在此之前,我已经写了几篇关于虚函数的总结,感兴趣的小伙伴儿可以查看这几篇文章:

《基础知识 | 有趣的动态转换》

《基础知识 | C++ 虚函数简介》

《基础知识 | c++ 有趣的动态转换之 delete 崩溃探究兼谈基类虚析构的重要性》

《基础知识 | 函数基础 1 —— 基本概念 & 如何调用外部模块的函数》

《基础知识 | 函数基础 2 —— 如何不依赖外部模块却能调用它的函数?》

《基础知识 | 函数基础 3 —— 跨模块调用未导出虚函数的各种姿势 》

本文主要关注以下两个问题,如果你已经有了很明确的答案,可以跳过本文:

  • 如果在编译 A 模块的时候,Test 类的虚函数声明的顺序是 Test1, Test2, Test3,但是在 B 模块编译的时候,Test 类头文件中虚函数顺序变成了 Test2, Test1, Test3。在 B 模块中调用 test->Test1(),调用的是哪个函数呢?
  • 假设 A 模块代码不变,但是在编译 B 模块的时候,Test 类的头文件中又多了一个虚函数 Test4(),在 B 模块中调用 test->Test4(),代码可以正常编译吗?会有链接问题吗?如果可以正常编译链接,运行的时候会有问题吗?
阅读全文 »

基础知识 | 函数基础 3 —— 跨模块调用未导出虚函数的各种姿势

发表于 2024-09-14 | 更新于: 2024-12-21 | 分类于 基础知识
字数统计: | 阅读时长 ≈ 分钟

缘起

在上篇文章 《基础知识 | 函数基础 2 —— 如何不依赖外部模块却能调用它的函数?》中,我们明白了一个事实 —— 可以在不依赖外部模块的情况下通过类对象指针调用其虚函数。

但是遗留了几个问题,如下:

  • 问题 1:Interface1 类中没有声明构造函数,编译器生成的构造函数保存在哪里?GetInterface 模块还是 Interface 模块?

  • 问题 2:Interface1 的虚表保存在哪里?GetInterface 模块还是 Interface 模块?

  • 问题 3:如果去掉 Interface1 中虚函数的导出符号,上述代码能编译通过吗?

  • 问题 4:如果在 Interface1 中声明了未导出的构造函数,上述代码能编译通过吗?

  • 问题 5:如果 InterfaceBase::Test1() 不是纯虚函数,上述代码能编译通过吗?

  • 问题 6:如果 InterfaceBase 的析构函数不是虚函数,上述代码能编译通过吗?

本文力求把这几个问题弄清楚。如果您对以上问题已经有了答案,可以跳过本文。

阅读全文 »

基础知识 | 函数基础 2 —— 如何不依赖外部模块却能调用它的函数?

发表于 2024-07-27 | 更新于: 2024-12-21 | 分类于 基础知识
字数统计: | 阅读时长 ≈ 分钟

缘起

前一段日子,同事遇到了一个奇怪的现象 —— B 模块调用了 A 模块某个类的成员函数,没有依赖 A 模块,编译时没有报错。而 C 模块也调用了 A 模块中同一个类的成员函数,没有依赖 A 模块,编译时却报了链接错误。

简单语音沟通后觉得不太可能。用了 A 模块的函数,却不依赖 A 模块,有点儿不讲道理!

因为当时我没在电脑前,跟同事简单沟通了几个可以设置库依赖的位置,结果都没有发现对应的依赖项。

心里越发觉得不可思议,难道 B 模块是通过其它方式依赖 A 模块的?正常情况下,如果 B 模块依赖 A 模块,一定可以在 B 模块的导入表中看到 A 模块相关的记录。于是建议同事查看 B 模块的导入表,但是同事不太熟悉。因为项目比较急,遂建议同事在 C 模块中添加对 A 模块的依赖,先解决项目问题,后面有机会再调查具体原因。

直到最近才有时间调查这个问题,结果发现这个问题非常有意思 —— B 模块确实没有依赖 A 模块(B 模块的导入表中确实没发现 A 模块的相关项),但是 B 模块确实调用了 A 模块中的函数,而且不是通过 LoadLibrary() + GetProcAddress() 的方式调用的。

本文主要关注以下问题,如果你已经有了答案,可以跳过本文。

  • B 模块在什么情况下可以调用 A 模块中的函数,但是却不依赖 A 模块?
阅读全文 »

基础知识 | 函数基础 1 —— 基本概念 & 如何调用外部模块的函数

发表于 2024-07-13 | 更新于: 2024-12-21 | 分类于 基础知识
字数统计: | 阅读时长 ≈ 分钟

缘起

最近遇到了几个跟虚函数有关的问题,既有编译链接问题,又有运行问题,归根到底是基本功不扎实导致的问题。本文将会简单梳理一下函数相关的基本知识:

  • 函数是什么?
  • 函数调用约定有哪些?有什么作用?
  • 普通函数、类静态函数、类成员函数的区别是什么?
  • 什么时候会调用构造函数,什么时候会调用析构函数?
  • 调用虚函数与调用其它函数的区别是什么?
  • B 模块如何调用 A 模块的函数?

本文适合初学者,如果您已经有一定的开发经验,可以跳过本文。

阅读全文 »

调试实战 | 调试另外一个由于全局变量初始化顺序导致的 dll 加载失败问题(下)

发表于 2024-06-08 | 更新于: 2024-12-21 | 分类于 调试
字数统计: | 阅读时长 ≈ 分钟

缘起

在前面两篇文章中,应该算是彻底理清了项目中存在的两个问题。感兴趣的小伙伴儿可以参考《调试实战 | 调试另外一个由于全局变量初始化顺序导致的 dll 加载失败问题(上)》和 《调试实战 | 调试另外一个由于全局变量初始化顺序导致的 dll 加载失败问题(中)》。

在上篇文章的末尾提到一种情况

如果在 LoadDlls.exe 中也显式加载了 dll3.dll,还会不会崩溃呢?答案是可能崩溃,也可能不崩溃。

因为 RegisterInitCallback()内部更新数据时使用的是 map.insert(),这会导致一个问题 —— 如果 map 中已经存在相同的 key,那么 insert() 会失败,不会更新数据。

试想,如果显式加载 dll3.dll 成功,但是 dll3.dll 的基址变了。map 中保存的还是旧的无效地址,而不是新函数地址。

如果 dll3.dll 的基址没有发生变化,新函数地址与旧函数地址一样,程序可以非常“幸运”的正常运行。

本文通过实战来验证上文中的结论,什么情况下会崩溃,什么情况下不崩溃。

阅读全文 »

调试实战 | 调试另外一个由于全局变量初始化顺序导致的 dll 加载失败问题(中)

发表于 2024-05-12 | 更新于: 2024-12-21 | 分类于 调试
字数统计: | 阅读时长 ≈ 分钟

缘起

在上篇文章《调试实战 | 调试另外一个由于全局变量初始化顺序导致的 dll 加载失败问题(上)》中,解决了由于全局变量初始化顺序不对导致的崩溃问题。但是代码里还有一处非常隐蔽的 bug,今天继续介绍一下这个问题及对应的解决方法。

阅读全文 »

调试实战 | 调试另外一个由于全局变量初始化顺序导致的 dll 加载失败问题(上)

发表于 2024-03-23 | 更新于: 2024-12-21 | 分类于 调试
字数统计: | 阅读时长 ≈ 分钟

缘起

最近又遇到了一个程序功能不正常的问题,深入调查后发现与全局变量初始化顺序有非常大的关系,只不过这次更加隐蔽。

之前总结了两篇与全局变量初始化顺序有关的文章,感兴趣的小伙伴儿可以参考《调试实战 | dll 加载失败之全局变量初始化篇》 和 《调试实战 | 全局变量初始化顺序探究》。

阅读全文 »

2024 开工喽

发表于 2024-02-20 | 更新于: 2024-12-21 | 分类于 年度总结
字数统计: | 阅读时长 ≈ 分钟

回首 2023

回顾整个 2023 ,相比 2022 加班少了,工作没那么拼命了。

由于各种原因,年初立的 flag 好几个都没实现。

  • 公众号基本上处于鸽的状态
  • 也没分享技术视频
  • 语言倒是接触了一下 rust,但远没有达到能实战的地步
  • 嘴没管住,腿倒是迈开了

展望 2024

我对 2024 这个数字感到非常亲切,2024 = 1000 + 1024,两个一千

  • 今年的首要任务依旧是锻炼身体

    本来计划 2024 年跑步作为日常锻炼的方式,结果 2023 年最后一次从公司跑回家后膝盖疼,2024 只能偶尔跑跑了

  • 继续遛狗
    2023 花费了很大一部分时间在遛狗上,2024 继续努力。如果不是狗子的陪伴,估计我早抑郁了,感谢,感恩。
  • 坚持练习英语口语

    希望这次不要因为任何原因中断

  • 继续坚持分享技术文章

    遇到值得总结的问题,及时总结分享

  • 读一些非技术书籍

    之前看的书以技术书籍为主,2024 年争取多看些非技术的书籍

  • 做一些改变

    尽量熟悉 AI 相关的人和事

12…14
BianChengNan

BianChengNan

134 日志
33 分类
221 标签
RSS
GitHub 知乎 博客园
© 2019 — 2024 BianChengNan | 全博客共 字
0%