代码之家  ›  专栏  ›  技术社区  ›  LoveMeSomeCode

Visual Studio调试器voodoo

  •  3
  • LoveMeSomeCode  · 技术社区  · 16 年前

    好吧,考虑到我不太了解调试器是如何工作的,更不用说编辑和继续了,这也许不是什么了不起的事情。

    但是我想知道是否有人知道调试器在这个场景中对变量声明做了什么。我可以通过我的代码进行调试,向前移动执行行-通过变量的初始声明和赋值,代码仍然可以正常运行。如果它是一个值类型,那么它将具有它的默认值,对于引用类型,则为空。

    因此,如果我在声明变量之前创建一个使用变量的函数,它将不会编译,但是如果我使用调试器以这种方式运行它,它仍然可以毫无错误地运行。为什么会这样?这与不能在声明上放置断点这一事实有关吗?

    3 回复  |  直到 16 年前
        1
  •  4
  •   Jason Kleban    16 年前

    是的,这些声明更具结构性。它们是堆栈上调用方法时分配的局部变量的一部分。你不能打断他们,因为他们不会真的发生在你写它们的地方——它们不是指令。

    编译器不允许您在声明它们之前使用它们的原因主要是为了您的理智——您总是知道要查找声明。方法中变量的复杂范围将进一步说明这一点。

        2
  •  1
  •   Justin Ethier    16 年前

    根据文章 Gain performance by not initializing variables :

    在.NET中,公共语言运行库(clr)在创建所有变量后立即对其进行明确初始化。值类型初始化为0,引用类型初始化为空。

    可能调试器已经知道这些变量,要么是因为代码已经编译,要么(现在键入代码的可能性不大),但调试器足够聪明,可以检测到声明了变量。

        3
  •  1
  •   John Deters    16 年前

    我认为,因为您使用的是调试器,所以会混淆编译和执行这两种不同的活动,以及声明性和函数性这两种不同的语句类型。

    编译时,声明性语句告诉编译器为变量保留一些内存。上面写着“哦,你要声明一个名为”wombatcount“的整数;好的,我会取地址0x1234并为你保留四个字节,然后在它们上面贴上一个名为wombatcount的标签。”这在编译期间发生,在你运行代码之前很久。*

    当您在调试器中执行代码时,您正在运行代码,因此它已经知道了它为您保留的内存的每个字节。变量wombatcount已经与地址0x1234处的四个字节相关联,因此它可以随时立即访问和更改该数据,而不仅仅是在声明语句之后。当然,您的程序不能,但调试器可以。

    C语言语法要求在代码中使用内存之前声明内存,但这只是语言定义的一部分,而不是所有编译器的一个硬性和快速的要求。有些语言根本不需要预先声明变量,甚至有些古老的语言也可以在代码中的任何位置声明变量,而不仅仅是“在上面”使用变量。但是语言开发人员现在明白语言语法对于人类的理解是最重要的,并且不再是为了方便机器编码或帮助编译器编写者,所以现代语言语法通常是为了尽可能地帮助程序员而创建的。这意味着让事情不那么混乱,所以“声明必须在第一位”是一条帮助您避免错误的常见规则。

    (*更准确地说,我相信在.NET中,标签只在编译时与指针列表相关联,指针列表将在运行时保留内存,但在使用数据字节之前,不会实际分配数据字节。这种差异是内在的,对你的理解并不重要。重要的是声明性语句在编译期间提前声明标签。)