如何在发布版本中编译依赖于仅调试代码的assert()?

Dav*_*vid 3 delphi assert delphi-2010

等待!——这个问题并不像听起来那么愚蠢。标题很简单。

我有一些调试代码来验证数据结构的正确性,还有一些断言检查此正确性,我只想在调试版本中启用它们:

{$ifdef DEBUG}
  function Sorted : Boolean;
  function LinearSearchByValue(const T : TType) : NativeInt;
{$endif}
Run Code Online (Sandbox Code Playgroud)

然后在一个方法中:

assert(Sorted);
Run Code Online (Sandbox Code Playgroud)

例如。

在我启用断言的调试版本中,一切都很好。然而,在我禁用断言的发布版本中,该行assert(Sorted);会导致编译器错误E2003 Undeclared identifier: 'Sorted'。完全正确,标识符没有声明,但是断言也被关闭,不应该被评估或生成任何代码。(尝试通过声明方法来欺骗断言,但没有实现会导致正常错误“不满意的前向或外部声明”。它显然也在寻找方法主体。)

这会导致一些混乱的代码,其中根本不应该存在于发布版本中的方法必须被声明并具有主体,以便编译断言,而断言被关闭。

在 Delphi 2010 中,如何声明仅存在于调试版本中的方法,并在断言中使用那些也应仅存在于调试版本中的方法?

更多信息:

  • 我尝试用 包装方法声明{$ifopt C+},它检查断言是否打开。调用assert仍然失败,并出现“未声明的标识符”。

  • 编译器选项肯定是断言被关闭。(我检查了 :))

  • 我尝试将assert使用这些方法的调用包装为{$ifdef DEBUG}. 然而,这很混乱并且不应该是必需的。有一次,它让我担心即使在发布版本中也会编译断言,并且出于性能原因我根本不需要它们。(这没有发生 - 未生成断言代码。)

  • 我当前的策略是始终声明这些方法,但在发布版本中构建 ifdef 方法主体并用虚拟结果填充它。这里的目标是编译所有断言,但方法的开销尽可能小,并且它们的返回值(如果它们实际上在发布版本中被调用)显然是错误的。

  • Delphi 中是否有与 C/C++ 风格的宏等效的东西,ASSERT(x)在发布版本中,宏将被简单地定义为空,导致编译器既看不到也不关心断言内的语句?这是在 C++ 中使用宏的少数干净方法(IMO)之一。

因此,虽然未生成断言,但它们已被编译。这又回到了我的问题:如何最好地混合仅调试方法和断言以及发布版本?

Rob*_*edy 5

不要从您的发布版本中排除该代码。将代码保留在那里,并无条件编译它。

您反对将代码存在于发布版本中的论点是它“混乱”。但代码你已经写好了,所以无论编译与否都会很乱。你不妨让编译器编译它;毕竟,编译额外的代码并不会花费更长的时间。

尝试排除与断言相关的代码只会因为需要条件编译指令而使您的代码变得更加混乱。

断言和调试信息是正交设置。当不进行调试时可以启用断言,反之亦然。

另一种方法是将与断言相关的代码移至单元测试中。然后,它们会自动从应用程序的所有版本中排除,但仍可用于测试。

  • @RobKennedy:我部分同意 - 相信编译器不链接它们通常是可以的。但本例中的条件编译是因为这些方法不是普通类接口的一部分。它们仅用于调试时检查,如果它们被意外包含在发布代码中将会很危险。因此,它们被定义为仅用于调试。IMO 应该不可能在发布版本中存在这些方法:未声明、未实现、不在 IDE 洞察中等。这可能是一种特殊情况,但我怀疑这种情况如此罕见,以至于通常无效。 (2认同)