Oudere Delphi-code bevatte soms een kleine _ftol-helper om een floating-pointwaarde naar een integer te converteren. In 32-bit projecten was het gebruikelijk om zo'n helper met inline assembler te schrijven, vooral in grafische en PDF-code die voor oudere compilers was geoptimaliseerd.
|
1 2 3 4 5 6 7 8 |
function _ftol( f: double) : Integer; cdecl; begin asm lea eax, f fstp qword ptr [eax] end; result := Trunc(f); end; |
Die aanpak breekt wanneer dezelfde unit voor een 64-bit target wordt gecompileerd. De Delphi 64-bit compiler meldt E1025 Unsupported language feature: 'ASM' omdat DCC64 geen gemengde Pascal en inline assembly binnen normale Pascal-routines ondersteunt.
Waarom de 64-bit compiler dit weigert
DCC64 kan 64-bit assembly-routines assembleren, maar de routine moet als volledige assembler-routine worden geschreven met de 64-bit calling convention in gedachten. U kunt 32-bit inline assembler niet in een Pascal-functiebody kopiëren en verwachten dat de compiler registergebruik, stackindeling of x87-gedrag vertaalt.
Een volledige assemblerversie is mogelijk, en code zoals hieronder toont het soort control-word-afhandeling dat nodig kan zijn wanneer de waarde al op de FPU-stack staat.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function _ftol: Integer; cdecl; // Assumes double value is in FPU stack on entry // Make a truncation to integer and put it into function result var TmpVal: Int64; SaveCW, ScratchCW: word; asm .NOFRAME fnstcw word ptr [SaveCW] fnstcw word ptr [ScratchCW] or word ptr [ScratchCW], 0F00h ;// trunc toward zero, full precision fldcw word ptr [ScratchCW] fistp qword ptr [TmpVal] fldcw word ptr [SaveCW] mov rax, TmpVal end; |
Geef de voorkeur aan Pascal wanneer alleen truncatie nodig is
Voor de meeste applicatiecode is de assemblerroutine niet nodig. Als de echte eis is om een Double naar nul toe af te kappen en een integerwaarde terug te geven, is de duidelijke en portable versie simpelweg:
|
1 2 3 4 |
function _ftol(f: double): integer; cdecl; begin Result := Trunc(f); end; |
Trunc drukt de bedoeling direct uit, compileert voor zowel 32-bit als 64-bit targets en vermijdt de onderhoudskosten van architectuurspecifieke assembler. Toekomstige onderhouders kunnen ook eenvoudiger redeneren over range checking en overflowgedrag.
Migratierichtlijnen
- Gebruik de Pascal-implementatie wanneer u de call site beheert en alleen numerieke conversie nodig hebt.
- Behoud een assembler-export alleen wanneer binaire compatibiliteit een specifiek symbool en calling convention vereist.
- Kopieer geen 32-bit registercode naar een 64-bit routine zonder de calling convention en gegevensbreedte te beoordelen.
- Test randgevallen zoals negatieve waarden, grote waarden en waarden buiten het bereik van het doel-integertype.
Bereik en gedrag
Het vervangen van assembler door Trunc moet nog steeds als een gedragswijziging worden behandeld die tests verdient. Bevestig hoe uw code moet omgaan met negatieve getallen, fracties vlak bij een integergrens en waarden buiten het bereik van Integer. De oude assembler kan afhankelijk zijn geweest van de FPU control-wordstatus, terwijl de Pascal-versie de RTL-implementatie voor de doelcompiler volgt.
Als de helper in een PDF- of grafische component zit, test dan uitvoer met geroteerde tekst, geschaalde coördinaten en getransformeerde tekenopdrachten. Die gebieden tonen subtiele conversieverschillen van float naar integer eerder dan eenvoudige voorbeelden.
Aanbevolen migratiepad
Vervang eerst private conversiehelpers waar mogelijk door duidelijke Pascal-code. Behoud daarna de oorspronkelijke 32-bit implementatie alleen achter een 32-bit conditional als die nog nodig is. Voeg pas een aparte 64-bit branch toe wanneer een gemeten prestatie- of binaire-compatibiliteitseis dat rechtvaardigt. Zo blijft het portable pad eenvoudig en wordt het architectuurspecifieke pad de uitzondering in plaats van de standaard.