【问题标题】:Why does _GLIBCXX_DEBUG have to be set in first line?为什么 _GLIBCXX_DEBUG 必须在第一行设置?
【发布时间】:2019-08-28 11:50:11
【问题描述】:

我在下面的无用程序中在 gcc 中设置调试模式:

#define _GLIBCXX_DEBUG 1
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector<int> v{1,2,3};
    for(int i=0; i<100000000000000;i++)
    cout<<v[i];
}

程序让我知道我的索引超出范围。但是,如果我颠倒前两行的顺序,我不会收到这样的错误消息(#include 在#define 之前)。为什么是这样?有没有办法在程序的另一行上切换调试模式(没有编译器标志)?我问是因为我正在解决 Leetcode.com 上的问题,我无法传递编译器标志或修改问题的第一行。

【问题讨论】:

  • 我不相信这是对stackoverflow.com/questions/31816095/… 的直接欺骗,所以我重新打开了它。但该链接中的建议仍然适用。
  • @NeilButterworth 谢谢,它肯定不是,因为如果我只包含 iostream 和 vector,问题仍然是完全相同的。
  • 请相应地编辑您的问题。
  • @NeilButterworth Cm'on #define _GLIBCXX_DEBUG 1 #include &lt;bits/stdc++.h&gt; using namespace std; 可能是你能做的最糟糕的事情。
  • 就您的用例而言,您始终可以在提交之前在本地编译和测试,或者使用 Wandbox 等在线环境。

标签: c++ gcc g++


【解决方案1】:

为什么必须在第一行设置调试模式?

因为受宏影响的是标准库头文件。如果您之前包含标题,则包含的定义将看不到宏定义。考虑以下示例,并假设它是标准头文件中包含的函数定义:

#define _GLIBCXX_DEBUG 1

inline void foo() {
#ifdef _GLIBCXX_DEBUG
    std::cout  << "debug mode is enabled";
#else
    std::cout  << "debug mode is not enabled";
#endif
}

对比:

inline void foo() {
#ifdef _GLIBCXX_DEBUG
    std::cout  << "debug mode is enabled";
#else
    std::cout  << "debug mode is not enabled";
#endif
}

#define _GLIBCXX_DEBUG 1

有没有办法在程序的另一行切换调试模式(没有编译器标志)?

在包含标准标头之后没有。

在这种情况下,您可以使用std::vector::at 代替下标运算符。即使没有调试模式,它也会诊断出越界访问。

【讨论】:

    【解决方案2】:

    #… 开头的任何内容都是对C++ preprocessor 的指令,它在实际的C/C++ 编译器之前运行;预处理器为编译器构造最终的源代码。

    这就是你的程序编译时发生的事情。

    第一步:预处理

    预处理器自上而下读取您的代码并执行指令。

    #define _GLIBCXX_DEBUG 1
    

    将名为_GLIBCXX_DEBUG 的标志设置为1

    #include <vector>
    #include <iostream>
    

    从编译器的包含路径中读取文件vector.hiostream.h。该文件包含更多 C/C++ 代码以及现在递归展开的预处理器指令。其中一些代码可能看起来像

    #if _CLIBCXX_DEBUG
    prinf("Print me to debug!");
    #endif
    

    并且此代码显示在您的最终 C/C++ 中。如果您的_CLIBCXX_DEBUG0,那么代码将不存在。最终效果是您可以在编译之前将代码放在一起。

    在您的情况下,额外的代码会在您的最终 C/C++ 文件中添加特殊测试,这会导致您看到错误消息。换行时,处理#include时不会设置标志,因此这些特殊测试不会添加到您的源代码中。

    请参阅this question,了解如何转储实际正在编译的最终 C/C++ 代码。

    第二步:编译

    一旦您的 C/C++ 源代码文件经过预处理(即包含的内容、有条件展开等……),就会调用实际的编译器来构建您的代码。

    有没有办法在程序的另一行切换调试模式(没有编译器标志)?

    根据需要在整个代码中更改该标志的值。

    【讨论】:

    • "根据需要在整个代码中更改该标志的值。"你能给我一个具体的例子吗?你下面的答案说在包含标准标题后这是不可能的,所以我不确定该相信哪个
    • 尝试添加#define _GLIBCXX_DEBUG 0 这两个包括?但是,此时您的向量定义已包含在启用的调试代码中。
    • @Jens,根据您自己的回答,这是行不通的,因为预处理器自上而下地进行包含,然后在为时已晚时进行定义。
    • @user3586940 你想达到什么目的?如果您想禁用额外的调试代码,请将_GLIBCXX_DEBUG 设置为0,如果您确实需要在程序中添加额外的调试代码,请将其设置为1。但是你的包含...之前这样做
    • @Jens 我在一个想要切换调试模式的环境中,但我无法修改编译标志或标准头文件的包含顺序。似乎没有办法完成我想做的事情。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-15
    • 1970-01-01
    相关资源
    最近更新 更多