Delphi 如何让依赖于仅调试代码的assert()在发布版本中编译?
等等这不是一个听起来那么愚蠢的问题。标题简单明了 我有一些调试代码来验证数据结构的正确性,还有一些断言来检查这种正确性,我只希望在调试构建中启用:Delphi 如何让依赖于仅调试代码的assert()在发布版本中编译?,delphi,delphi-2010,assert,Delphi,Delphi 2010,Assert,等等这不是一个听起来那么愚蠢的问题。标题简单明了 我有一些调试代码来验证数据结构的正确性,还有一些断言来检查这种正确性,我只希望在调试构建中启用: {$ifdef DEBUG} function Sorted : Boolean; function LinearSearchByValue(const T : TType) : NativeInt; {$endif} 然后在一种方法中: assert(Sorted); 比如说 在启用断言的调试构建中,一切正常。但是,在禁用断言的发布版本
{$ifdef DEBUG}
function Sorted : Boolean;
function LinearSearchByValue(const T : TType) : NativeInt;
{$endif}
然后在一种方法中:
assert(Sorted);
比如说
在启用断言的调试构建中,一切正常。但是,在禁用断言的发布版本中,行assert(排序)代码>导致编译器错误E2003未声明的标识符:“已排序”
。这是非常正确的,标识符没有声明,但是断言也被关闭,不应该被计算或生成任何代码。(试图通过声明方法但没有实现来欺骗assert会导致正常错误“未满足前向或外部声明”。它显然也在寻找方法体。)
这导致了一些混乱的代码,在这些代码中,发布版本中根本不应该存在的方法必须声明并具有一个主体,以便编译断言,而断言被关闭
在Delphi 2010中,我如何声明只存在于调试版本中的方法,并使用那些应该也只存在于调试版本中的断言?
进一步资料:
- 我尝试用
{$ifopt C+}
包装方法声明,检查断言是否打开。调用assert
仍然失败,标识符为“未声明”
- 编译器选项肯定是关闭断言。(我勾选:)
- 我已尝试将使用这些方法的
{$ifdef DEBUG}
的assert
调用包装起来。然而,这是混乱的,不应该被要求。有一点让我担心,即使在发布版本中也会编译断言,出于性能原因,我根本不想要它们。(这不会发生-不会生成断言代码。)
- 我目前的策略是一直声明这些方法,但在发布版本ifdef中,方法体将被释放,并用一个伪结果填充。这里的目标是编译所有断言,但方法的开销尽可能小,并且它们的返回值(如果它们在发布版本中实际被调用)显然是错误的
- Delphi中是否有与C/C++风格的宏等价的宏,在Delphi中,
ASSERT(x)
宏只会在发布版本中定义为nothing,从而导致编译器既看不到也不关心断言中的语句?这是少数几个在C++中使用宏的清洗方法(imo)。
因此,虽然没有生成断言,但它们是编译的。这又回到了我的问题:如何最好地混合使用纯调试方法和断言以及发布版本?不要将代码从发布版本中排除。将代码保留在那里,并无条件编译它
您反对将代码存在于发布版本中的理由是它“凌乱”。但您已经编写了代码,因此无论是否编译,它都将是凌乱的。你也可以让编译器编译它;毕竟,编译额外的代码不会花费太多时间
试图排除与断言相关的代码只会因为需要条件编译指令而使代码更加混乱
断言和调试信息是正交设置。当不进行调试时,可以启用断言,反之亦然
另一种方法是将断言相关的代码移动到单元测试中。然后,它们将自动从应用程序的所有版本中排除,但仍可用于测试。断言通常被“省略”或不包含在编译过程中链接步骤的输出可执行代码中。传递到assert函数的源代码符号和表达式必须在编译步骤中定义,以便编译器可以分析和生成断言及其表达式参数的代码
将代码复制到输出文件时,链接器将确定输出exe中是否包含断言。根据编译器的不同,传递给assert的表达式可能仍然包含在可执行代码中,即使没有包含对assert函数的调用
正如在其他答案和许多评论中所指出的,断言并不是调试所独有的。断言在发布代码中也很有价值,可以验证在条件不允许的情况下决不能发生
允许您在发布代码中保留断言,同时使断言表达式中使用的函数仅存在于调试版本中的一种解决方案是为发布版本定义调试函数的do nothing存根。像这样:
// Declaration:
private function Sorted: Boolean;
// Implementation
{$ifdef DEBUG}
function Sorted : Boolean;
begin
// work work work
end;
{$else}
function Sorted: Boolean;
begin
end;
{$endif}
// used in an assertion:
assert(Sorted);
这允许您在调试代码和发行版代码中使用断言,而不会在断言周围使用ifdef包装器污染源代码,并保证发行版代码中不存在调试实现。我想您已经列举了您的选项。您只需要决定使用哪一个。我不会使用虚拟结果,我会提出EAssertionFailed
,因为您永远不会到达那里。事实上,我有一个名为raiseasertionfailed
的实用函数来完成这个任务。@Rob Kennedy,你错了Assert
compiler magic具有其他情况下不可用的唯一属性,是检查始终为真条件的正确工具。我之前的评论是正确的,@User。Mad Except、JclDebug和Eureka Log都允许程序从异常中发现文件名、行号和大量附加信息,并且都不需要使用Assert
来获取异常。运行时不会引发异常,因为您永远不会调用该代码。我的代码中到处都是这样的东西。例如,枚举类型的case语句的else子句。我总是把Ra