在system.pas 里 Assert 的实现是:
procedure _Assert(const Message, Filename: AnsiString; LineNumber: Integer);
{$IFDEF PUREPASCAL}
begin
if Assigned(AssertErrorProc) then
AssertErrorProc(Message, Filename, LineNumber, Pointer(-1))
else
Error(reAssertionFailed); // loses return address
end;
{$ELSE}
asm
PUSH EBX
{$IFDEF PIC}
PUSH EAX
PUSH ECX
CALL GetGOT
MOV EBX, EAX
MOV EAX, [EBX].AssertErrorProc
CMP [EAX], 0
POP ECX
POP EAX
{$ELSE}
CMP AssertErrorProc,0
{$ENDIF}
JNZ @@1
MOV AL,reAssertionFailed
CALL Error
JMP @@exit
@@1: PUSH [ESP+4].Pointer
{$IFDEF PIC}
MOV EBX, [EBX].AssertErrorProc
CALL [EBX]
{$ELSE}
CALL AssertErrorProc
{$ENDIF}
@@exit:
POP EBX
end;
{$ENDIF}
可以看出AssertErrorProc() 是没有初值的,通过对其赋值可以定义自己的Assert处理过程,另如果未对AssertErrorProc赋值,将调用Error()处理过程来做为异常处理.
TAssertErrorProc = procedure (const Message, Filename: string;
LineNumber: Integer; ErrorAddr: Pointer);
{$ASSERTIONS OFF/ON} 开关来决定Assert是否被调用.可以在project-option-complier里设置.
这样就可以在beta或debug版本是打开,而最终发布时关闭调试输出了.
一个简单的AssertErrorProc 例程:
unit AssertLogs;
interface
implementation
uses
Windows,
SysUtils;
var
runErrMsg : String;
oldAssertErrorProc : TAssertErrorProc;
procedure LogAssert(const Message, Filename: string; LineNumber: Integer; ErrorAddr: Pointer);
begin
runErrMsg := format(’Error: %s, Addr: %p, in file(%d): %s ’,
[Message, ErrorAddr, LineNumber, FileName]);
if IsConsole then
Writeln(runErrMsg)
else
MessageBox(0, pChar(runErrMsg), ’Error Log by AssertLogs’, 0);
end;
initialization
oldAssertErrorProc := AssertErrorProc;
AssertErrorProc := @LogAssert;
finalization
AssertErrorProc := oldAssertErrorProc;
end.
*************************************
那么在output debug信息时只需要:
Assert(false,outputstring);