WARNUNG: Obwohl die folgende Antwort die gestellte Frage anspricht, würde ich empfehlen, dass niemand sie jemals verwendet. Wenn Sie eine andere Rundung als Round
durchführen möchten, schreiben und rufen Sie eine dedizierte Funktion auf.
Sie können einen Laufzeitcode Haken verwenden, um die Implementierung von Round
zu ändern.
Die Falte ist, dass es ein wenig schwierig ist, die Adresse der Round
Funktion zu bekommen, obwohl es ein intrinsischer ist. Sie müssen auch darauf achten, die verwendete Aufrufkonvention zu befolgen. Der Eingabewert wird im x87-Stack-Register ST(0)
übergeben und der Rückgabewert ist eine 64-Bit-Ganzzahl in EDX:EAX
.
So geht's.
procedure PatchCode(Address: Pointer; const NewCode; Size: Integer);
var
OldProtect: DWORD;
begin
if VirtualProtect(Address, Size, PAGE_EXECUTE_READWRITE, OldProtect) then
begin
Move(NewCode, Address^, Size);
FlushInstructionCache(GetCurrentProcess, Address, Size);
VirtualProtect(Address, Size, OldProtect, @OldProtect);
end;
end;
type
PInstruction = ^TInstruction;
TInstruction = packed record
Opcode: Byte;
Offset: Integer;
end;
procedure RedirectProcedure(OldAddress, NewAddress: Pointer);
var
NewCode: TInstruction;
begin
NewCode.Opcode := $E9;//jump relative
NewCode.Offset :=
NativeInt(NewAddress)-NativeInt(OldAddress)-SizeOf(NewCode);
PatchCode(OldAddress, NewCode, SizeOf(NewCode));
end;
function System_Round: Pointer;
asm
MOV EAX, offset [email protected]
end;
procedure _ROUND;
asm
{ -> FST(0) Extended argument }
{ <- EDX:EAX Result }
// your implementation goes here
end;
initialization
RedirectProcedure(System_Round, @_ROUND);
Wenn Sie lieber Ihre Version in Pascal als asm implementieren, dann müssen Sie die Nicht-Standard-Aufrufkonvention von _ROUND
zum Standard Delphi-Aufrufkonvention anzupassen. Gefällt mir:
function MyRound(x: Extended): Int64;
begin
// your implementation goes here
end;
procedure _ROUND;
var
x: Extended;
asm
{ -> FST(0) Extended argument }
{ <- EDX:EAX Result }
FSTP TBYTE PTR [x]
CALL MyRound
end;
Beachten Sie, dass ich hier angenommen habe, dass Ihr Programm 32 Bit zielt. Wenn Sie 64 Bit zielen müssen, dann sind die Prinzipien sehr ähnlich, aber die Details unterscheiden sich offensichtlich.
Nach http://docwiki.embarcadero.com/Libraries/XE2/en/System.Round das Verhalten von System.round tatsächlich eingestellt werden kann. – RobS
Sie können nur neue Einheit mit published 'function Round (extended): extended 'erstellen, diese Einheit in den' uses'-Abschnitt jeder Ihrer Quelldateien aufnehmen und neu kompilieren. Wenn Sie nicht den vollständig qualifizierten Namen verwenden (und fast niemand tut es für die allgegenwärtige RTL-Funktion), dann wäre Ihre neue Funktion bei der e-Kompilierung besser sichtbar als 'System.Round'. Das Ändern des globalen Verhaltens kann Folgen für einige Drittanbieter-Code in Ihrem Programm haben, –
Zustimmen - das ist der einfachste Ansatz. +1 –