zoukankan      html  css  js  c++  java
  • 神秘的 _DEBUG 宏从何处来?

    神秘的 _DEBUG 宏从何处来?

    缘起

    在上一篇文章 《调试实战 —— dll 加载失败之Debug Release争锋篇》中,由于两个工程中的 _ITERATOR_DEBUG_LEVEL 不同,导致了对同一个 map 的解析不同,从而导致了崩溃。在示例代码中,我是手动更改的该宏的值,在实际工程中,却另有玄机。在上文中故意省略了这部分内容的介绍。现把实际工程的问题在本文中做个相对详细的梳理总结。

    先剧透一下:实际工程中的问题是因为一个工程中定义了 _DEBUG 宏,另外一个工程里没定义。但是我已经核对过,两个工程都没定义 _DEBUG 宏。其中一个工程的 _DEBUG 宏是从哪儿来的呢?

    测试工程简介

    为了查出 _DEBUG 宏从何而来,我特意建了一个超级简单的工程。只包含一个源文件,其内容如下:

    #ifdef _DEBUG
    #pragma message("---- _DEBUG defined.")
    #else
    #pragma message("---- _DEBUG NOT defined.")
    #endif
    
    int wmain()
    {
    	return 0;
    }

    相信大家都知道,debug 会定义 _DEBUG 宏,而 release 不会定义 _DEBUG 宏。默认的 debugrelease 中对应的 Preprocessor definition 配置对比如下图:

    preprocessor-definitions-comparation
    preprocessor-definitions-comparation

    最开始,我以为简单的删掉 _DEBUG 宏,编译的时候就不会有 _DEBUG 宏了。

    删除 _DEBUG 宏
    删除 _DEBUG 宏

    没想到……

    顽强的 _DEBUG 宏

    再次编译的时候, _DEBUG 宏还是被定义了。

    compile-result
    compile-result

    误入歧途

    根据经验,工程配置可以直接存储在工程文件(后缀一般是 .vcxproj),也可以存储在 .props 文件中。在 TestDebugMacro.vcxproj 中搜索 _DEBUG 宏,一无所获!会不会存储在 .props 中呢?使用 File Locator 搜索关键字 _DEBUG,搜索条件如下图:

    search-_DEBUG-macro-in-props
    search-_DEBUG-macro-in-props

    只搜到了几条相关的记录,因为使用的是 vs2013,对应的版本号是 v120,所以只需要关注高亮的搜索记录。

    虽然,看上去不太可能,但是抱着试试看的心态,删除 Microsoft.Cpp.AppContainerApplication.props104 行的 _DEBUG 宏,

    重新编译。结果, _DEBUG 宏,依然顽强的活着。这里就不截图了。

    会不会记录在注册表里呢?搜索一番,一无所获!

    肯定是记录到哪里了,应该不会动态生成吧?!

    继续搜索

    扩大搜索范围,在所有文件中搜索,经过排查,只有 cl.exe 中的记录比较靠谱。

    search-_DEBUG
    search-_DEBUG

    难道写死在 cl.exe 中了?有点儿不可思议。(文中暗表,确实写死在 cl.exe 中了。)

    顺着这条路已经找不到更多有价值的线索了,需要换个思路了。

    换个思路

    会不会是 vs 在编译的时候,根据某些条件自动添加的?为了排除这种情况,直接使用 msbuild.exe 进行构建操作(在 《全局变量初始化顺序探究》里已经介绍过了)。

    build-with-msbuild
    build-with-msbuild

    可以发现,直接使用 msbuild.exe 编译也会定义 _DEBUG 宏。可以把 vs 从怀疑名单中划掉了。

    注意看传递给 cl.exe 的参数(上图黄色高亮部分)中也没有 _DEBUG 宏的踪影。

    难道是 msbuild 通过进程通信手段实现的?(真佩服自己的脑洞)

    试试直接使用 cl.exe TestDebugMacro.cpp 编译。

    柳暗花明

    居然 _DEBUG 宏消失了!!!

    compile-with-cl
    compile-with-cl

    通过 msbuild.exe 启动的 cl.exe ,从日志可以发现 cl.exe 的参数如下:

    C:Program Files (x86)Microsoft Visual Studio 12.0VCinCL.exe /c /ZI /nologo /W3 /WX- /Od /Oy- /D WIN32 /D _CONSOLE /D _LIB
       /D _UNICODE /D UNICODE /Gm /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Fo"Debug\" /Fd"Debugvc120.pdb" /Gd /TP
       /analyze- /errorReport:queue TestDebugMacro.cpp

    而手动执行的 cl.exe 只传递了需要编译的文件名。会不会是哪个神奇的参数搞的鬼呢?好办,二分法排查!

    经过几次尝试,很快定位到是 /MDd 搞得鬼!

    compare-cl-param
    compare-cl-param

    /MDd 选项是何方神圣?搜索一下,很快找到了微软官方的介绍。

    /MDd 选项

    官方文档很明确的描述到:/MDd 选项会定义 _DEBUG_MT_DLL ,并且会使用调试 版本的多线程运行时库。

    具体请介绍参考微软官方文档截图:

    mdd-option-msdn
    mdd-option-msdn

    贴一张工程属性设置截图。

    set-mdd-option-in-vs
    set-mdd-option-in-vs

    反思

    当时没有严格按照对比的思路进行排查,浪费了很多时间!

    很久之前确实对比过 /MDd 几种选项的不同,当时的关注点主要在于会链接不同的运行时库,忽略了对宏的影响。相信经过这次折腾,我永远也忘不了 /MDd 选项定义 _DEBUG 宏。这个行为不是通过配置文件发生的,而是写到了 cl.exe 的文件中!

    总结

    • File Locator 真可谓文件内容搜索神器,经常排错的小伙伴儿必备!
    • 一种情况是正常,一种情况不正常,最简单粗暴有效的办法就是对比
    • 排查问题时,我们要尽量简化问题,尽可能排除无关条件的干扰。
    • /MDd 选项不仅会影响链接库,还会定义 _DEBUG 宏。

    参考资料

    https://docs.microsoft.com/en-us/cpp/build/reference/md-mt-ld-use-run-time-library?view=vs-2019

  • 相关阅读:
    JavaAPI基础(1)
    类与对象、封装、构造方法
    Java语言基础
    Request请求的应用
    Response的应用
    java生成动态验证码
    Servlet的配置
    常见的状态码。。
    简单学习【1】——打包JS
    NodeJS2-2环境&调试----引用系统内置模块,引用第三方模块
  • 原文地址:https://www.cnblogs.com/bianchengnan/p/13174125.html
Copyright © 2011-2022 走看看