为什么调试器不知道#define'd常量?

时间:2015-09-18 10:27:17

标签: c++ debugging visual-studio-2015

调试我的代码时,我经常想知道#define'd常量的值。但调试器似乎并不知道它们的值。这意味着我必须围绕查看包含路径等来查找#define行。是否有一些技巧可以让这更容易?

更新:我不得不向Tony D授予绿色标记以详细回答标题问题,但我也赞成使用const代替#define(I还测试了enum也有效。最后使用F12找到原始的#define线是另一个好主意。

7 个答案:

答案 0 :(得分:42)

对于谷歌值得的10分钟,似乎Visual Studio并不支持这一点。

有些编译器会尝试这样做,但有一个原因是它有点脆弱/尽力而为...

首先重新发布并删除对此的常见但虚假的解释:概念不同的预处理步骤,在预处理器宏的使用之前替换文本"正确&#34 ;编译开始,但真正没有理由预处理阶段无法通过#define#undef ine语句的记录以包含在其他语句中调试信息。

痛苦是指直觉上和通常被认为是什么" #define - 预处理器常数"不是什么......

const Some_Type some_identifier = some_value;

...因为后者在应用程序的名称空间层次结构中有一个特定的位置,实际上无法更改,而一个#define可以是#undef -en并重新#define d任意次数,以便"值"特定代码行中的预处理器宏的大小取决于该行如何包含在翻译单元中:每个翻译单元中相同行的每个包含可能具有不同的值(或没有值)对于那个宏

出于这个原因,显示"值"因为你通过某些代码调试宏是有问题的 - 它只保证在特定的翻译单元中的特定行有一个值,但程序员通常需要调试器根据源文件中的行显示和导航程序。

考虑:

  

use_x.h

class T ## X {
    void g() { ... }
};
  

some_app.cc

#define X 2783
#include "use_x.h"
#undef X
#define X 2928
#include "use_x.h"
void f() {
    const int last_x = X;
}

如果您的调试器在f()上面单步执行,X可以说是2928,但如果您正在逐步执行g()版本,该怎么办? 1}} - 调试器很难理解类名和用于创建它的X的值之间的某种联系,或者计算出以其他方式显示的内容....

如果将鼠标悬停在宏上而停在某个其他行 - 可能是从不同的翻译单元链接 - 会变得更糟 - 调试器无法知道您是否对最后一个值感兴趣您的执行已经通过的那个宏,或者执行继续时它可能具有的下一个值(如果它甚至可以预测可能首先发生的任何分支),或调试器行的宏的值(如果有的话)&# 39; s停在了。

因此,一些工具链(编译器/调试信息编码/调试器)只是不买这个烂摊子。更好的工具可能会跟踪简单的案例,然后不会显示任何内容 - 或者可能的值列表 - 用于分析过于复杂的案例。显示错误的值比没有错误。

它在调试器中没有帮助,但是当需要审核宏值/替换时,您可以尝试cl /E(对于GCC / clang选项' s -E)为翻译单元提供预处理输出 - 然后您可以看到预处理器进行了哪些替换。

答案 1 :(得分:16)

在编译之前,预处理器会评估和解析宏。这不仅仅是编译的程序不知道它们的值:编译的程序根本不包含它们的痕迹。您的调试器无需检查。

将宏视为代码生成工具,一切都将变得清晰。

某些编译器确实有一个标志,您可以设置该标志以保留各种预处理器定义的值,并将它们列在可执行文件的特殊区域中以进行调试。不过,我不知道如何在VS中实现这一点。我会使用相关的开关只运行 运行预处理器,然后检查结果。

答案 2 :(得分:4)

' #define' d常量是调试器未知的,因为它们在编译之前被预处理,并且它们在代码中的外观被替换为值。

如果你想要一个常量值,为什么不使用const?这样,您可以在调试器中看到该值,并强制编译器检查您错误地尝试更改代码中的值的任何位置。 #define没有那种安全性。

答案 3 :(得分:3)

关于“Visual Studio”,#define X 3在预处理期间被解析,X的所有外观都被替换为3.因此,当您将鼠标移到它上面时,调试器将不会显示其价值,就像任何其他具有“硬编码”价值的陈述一样。

int res = y + 3;

如果将鼠标移到3上,它将不会在浮动窗口中显示3。

答案 4 :(得分:2)

为什么他们不知道已被回答..我实际上感觉到你的痛苦。这就是为什么我开始的每个项目都实际上跟踪包含路径,并且在编译之前我grep路径以在列出定义的文本文件中获取定义。调试时我会随身携带。这是我猜的一个技巧:)

另外:也许真有帮助..我希望:) 我自己不再使用Visual Studio了,所以我不能100%确定2015年是否有可能,但是: - 在配置属性中将预处理设置为yes - > C / C ++ - >预处理。 - 用于生成.i文件的visual studio,我希望2015下次编译程序时仍然如此,因为这是预处理器的输出。 - 打开这个.i文件,您至少可以看到宏的实际扩展值,并在调试时在监视窗口中输入该值。

这只会花费你额外的编辑,但第二次帮助你,节省宝贵的时间,你可以花在其他东西而不是文件夹潜水:)

答案 5 :(得分:2)

在您想知道其值的行上选择您感兴趣的宏。

按F12。

这将跳转到它的定义(编译器可以解决这个问题:给定的代码行可以为同一个#define提供多个定义!)。

答案 6 :(得分:1)

#define one 1

这只是文字替换。甚至编译器也不知道代码中这个“1”背后的内容。

宏在编译/链接阶段之前由预处理器进行评估。

有关编译步骤的更多信息: How does the compilation/linking process work?