记一次 pugixml 编译错误的解决

记一次 pugixml 编译错误的解决

缘起

前一阵子,平台在换基线,底层接口变了很多,因此引出了至少 20000 个编译错误。在加班改完这些编译错误后,没想到又遇到了一个诡异的编译错误。而且之前还解决过类似的编译错误,但是这次却没能第一时间找出罪魁祸首。一起看看这是一个什么编译错误吧。

pugixml-compile-error
pugixml-compile-error

诡异吧?标准模板库里(参考 vector 的实现)大量使用了这种技法( c++ 中典型的 placement new)。为什么这里就不行了呢?

杀手锏

解决这种诡异的编译错误,杀手锏是查看预编译生成的文件。好在 vs 已经提供了相应的支持。

vs-preprocess-option
vs-preprocess-option

/P 表示将预处理的输出写入到文件中(每个 .cpp 文件会生成一个对应的 .i 文件)。

/C 表示保留注释。

可以在有问题的源码上方加上独特的标记 // TODO:BCN check here,这样可以通过搜索快速定位到错误的代码的位置。强烈建议这么做,因为预处理输出的文件实在是太大了。

查看输出结果

vs 中按上图所示设置好,然后重新编译,编译完成后会生成如下几个 .i 文件,如下图:

generated-preprocessed-files
generated-preprocessed-files

注意: 相对于 .cpp 文件,.i 文件非常巨大。在这个简单的示例工程中,即使没写什么业务代码,生成出来的文件都有 11 MB 多,实际项目中产生的 .i 文件达到几十兆,上百兆是很轻松的。

大多数情况下,可以很明确的知道要查看哪个 .i 文件(可以通过错误提示来判断)。但是本例比较特殊,不知道应该查看哪个 .i 文件(报错的文件是 pugixml.cpp ,但是生成的 .i 文件中并没有名为 pugixml.i 的文件)。

请出 File Locator,设置搜索目录为 .i 文件所在的目录,设置文件名为 *.i,并设置 Containing text"// TODO:BCN check here",点击 Start 开始搜索:

search-mark-using-file-locator
search-mark-using-file-locator

很快就得到了搜索结果 —— 文件 PugiXmlCompileErrorDlg.i 的第 664200 行。

使用 EditPad 打开 PugiXmlCompileErrorDlg.i,按 Ctrl + g ,在弹出的界面中的行号位置输入 664200 即可跳转过去。但是 EditPad 中的行号和 File Locator 给出来的行号不匹配,664200 行并不是期待的注释内容。没关系,按 ctrl + f 重新搜索一遍,瞬间就搜到了(感叹一下 EditPad 的强大)。

view-preprocessed-file-content-in-editpad
view-preprocessed-file-content-in-editpad

注意看高亮内容,本来应该是 new (memory) xml_attribute_struct(page); 的,但是却在 new(memory) 之间多了一段”奇怪“的字符串。

恍然大悟

看到这,我瞬间就明白是怎么回事了,相信有 MFC 开发经验的小伙伴儿应该也反应过来了:

DEBUG 版的 MFC 程序中,new 可能会被定义成 DEBUG_NEW

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

DEBUG_NEW 的定义如下:

// VC\atlmfc\include\afx.h
#define DEBUG_NEW new(THIS_FILE, __LINE__)

所以,new 最终被替换成了 new(THIS_FILE, __LINE__) ,于是就出现了这个奇怪的编译错误。

虽然找到了原因,但是还有一些细节没有弄清楚。

深入思考

  1. 为什么标准模板库中可以这么用?在 pugixml 里不能这么用?
  2. 为什么这个编译错误报在 pugixml.cpp 中?明明工程中并没有添加 pugixml.cpp 这个文件啊?

因为这两个问题都比较简单,本文不打算深入探讨,直接给出结论。

**问题1:**标准库可以这么用是因为 —— 在包含标准库中的头文件时,new 还是 new,没有被定义成 DEBUG_NEW。而 pugixml 有问题,是因为在包含 pugixml.hpp 之前,new 被定义成了 DEBUG_NEW。如下图:

compare-include
compare-include

说明: 实际项目远比示例代码要复杂。不是那么容易能看出来的。

**问题2:**因为如果定义了 PUGIXML_HEADER_ONLY 并且没有定义 PUGIXML_SOURCE, pugixml.hpp 会在内部包含 pugixml.cpp

include-pugixml_cpp_in_hpp_file
include-pugixml_cpp_in_hpp_file

是的,你没看错,源文件也是可以通过 #include 包含的。

解决

只需要把 #include "pugixml/pugixml.hpp" 移动到 #ifdef _DEBUG 上方即可。或者干脆注释掉 #define new DEBUG_NEW 这一行。

总结

  • 虽然之前解决过类似的问题,但是在耗费大量体力和脑力之后,很难保持清醒的头脑。
  • EditPad 是最近发现的文本编辑神器,轻松打开上百兆(甚至上千兆)的大文件,秒杀大多数其它文本编辑器。而且有免费版,强烈推荐一波。
  • vs 中,可以通过 /P 编译选项来输出预编译的结果到文件中(.i 后缀的文件)。
  • 并不是只有 .h 文件才能被 include.cpp 文件也可以被 include

考考你

什么情况下可以 #include xxx.cpp,什么情况下不能呢?为什么?

欢迎留言讨论交流。

参考资料

https://en.cppreference.com/w/cpp/language/new

https://en.wikipedia.org/wiki/Placement_syntax

https://www.enseignement.polytechnique.fr/informatique/INF478/docs/Cpp/en/cpp/memory/new/operator_new.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值