2012-02-17 172 views
3

我有以下功能在Delphi 2006中工作,但在Delphi XE2下,它在處理RET時給出訪問衝突錯誤或特權指令錯誤。德爾福XE2程序集

function Q_TrimChar(const S: string; Ch: Char): string; 
asm 
     PUSH ESI 
     MOV  ESI,ECX 
     TEST EAX,EAX 
     JE  @@qt 
     MOV  ECX,[EAX-4] 
     TEST ECX,ECX 
     JE  @@qt 
     PUSH EBX 
     PUSH EDI 
     MOV  EBX,EAX 
     MOV  EDI,EDX 
     XOR  EDX,EDX 
     MOV  EAX,ESI 
     CALL [email protected] 
     MOV  EDX,EDI 
     MOV  ECX,[EBX-4] 
@@lp1: CMP  DL,BYTE PTR [EBX] 
     JNE  @@ex1 
     INC  EBX 
     DEC  ECX 
     JNE  @@lp1 
     MOV  EDX,[ESI] 
     JMP  @@wq 
@@ex1: DEC  ECX 
@@lp2: CMP  DL,BYTE PTR [EBX+ECX] 
     JNE  @@ex2 
     DEC  ECX 
     JMP  @@lp2 
@@ex2: MOV  EDI,[ESI] 
     LEA  EDX,[EDI+ECX+1] 
@@lp3: MOV  AL,BYTE PTR [EBX+ECX] 
     MOV  BYTE PTR [EDI+ECX],AL 
     DEC  ECX 
     JNS  @@lp3 
@@wq: MOV  EAX,[ESI] 
     MOV  BYTE PTR [EDX],0 
     SUB  EDX,EAX 
     MOV  [EAX-4],EDX 
     POP  EDI 
     POP  EBX 
     POP  ESI 
     RET 
@@qt: MOV  EAX,ESI 
     CALL [email protected] 
     POP  ESI 
end; 

我不知道程序集很好。問題是什麼?

+1

順便說一句,這個asm代碼只是編碼非常好。例如,如果s字符串只是Ch的一個字符,它將會生成一個AV,恕我直言。忘掉它,然後使用Mike提供的第二個pascal版本作爲回答。 – 2012-02-17 08:22:11

+1

我投票結束,因爲這是如此狹義的定義。儘管有人似乎已經明確地回答了這個問題,但令人印象深刻的是,這類問題對網站的價值就像零。 – 2012-02-18 00:12:56

回答

17

我完全同意David的建議,只是在Pascal中編寫代碼,並提出了答案。除非分析表明這是一個真正的瓶頸,否則真的不需要ASM。這裏有兩個版本。第一個更容易閱讀,但第二個更高效:

function Q_TrimChar(const S: string; Ch: Char): string; 
begin 
    result := S; 
    while (result <> '') and (result[1] = Ch) do Delete(Result, 1, 1); 
    while (result <> '') and (result[Length(Result)] = Ch) do Delete(Result, Length(Result), 1); 
end; 

function Q_TrimChar(const S: string; Ch: Char): string; 
var 
    First, Last : integer; 
begin 
    First := 1; 
    Last := Length(S); 
    while (First < Last) and (S[First] = Ch) do inc(First); 
    while (Last >= First) and (S[Last] = Ch) do Dec(Last); 
    Result := copy(S, First, Last-First+1); 
end; 
+1

爲了實現代碼的實際工作,做得很好+1。第二個版本更好。當First = 1和Last = Length(S)時,明顯的優化不是調用複製。 – 2012-02-17 07:45:41

+0

+1。良好的編譯器生成的字符串操作例程很難打敗,特別是在這種簡單的情況下。我不認爲原始彙編程序比這裏提供的第二個pascal變種更快! – 2012-02-17 10:01:17

+0

@CosminPrund你說得對,第二個版本比原來的asm版本少bug,並且性能會相同 - 甚至可能更好,因爲恕我直言,asm版本是錯誤的(例如'S = Ch')。對於一個真正優化的關閉算法的asm版本,參見'函數Trim(const S:RawUTF8):RawUTF8;'在asm和pascal中[this unit](http://synopse.info/fossil/finfo?name=SynCommons .pas) - 我已經使用John O'Harrow的彙編程序,在Delphi 2009/2010/XE/XE2中進行了修改。 – 2012-02-17 12:26:23

6

Delphi 2006使用單字節ANSI字符,所以stringAnsiString,CharAnsiChar。在Delphi 2009及更高版本中,使用了兩個字節的Unicode字符。這個函數不可能適用於兩個編譯器。

即使使用AnsiString和AnsiChar的標準破解也不起作用。最有可能的是,這個函數對RTL實現的假設在現代Delphi中不再有效。

我會在Pascal中重寫這個函數,讓編譯器完成這項工作。這不僅是解決當前問題的最快捷方式,它還將幫助您跨越64位編譯的障礙,並且您可以選擇解決這個問題。

+1

downvoter會照顧評論嗎? – 2012-02-17 08:39:54

+2

提供的代碼中的主要問題並不是string/AnsiString問題,而是整個asm塊本身,由於各種寄存器佈局*和* LStrFromPCharLen API的新簽名,x64本身根本無法工作因爲德爾福2009年。 – 2012-02-17 12:17:53

+1

@Arnaud我發現批評相當薄弱。 x64在旁邊。 OP正在編譯32位。該代碼在32位XE2中不起作用。它在32位2010或XE中也不起作用。再加上我評論了x64位,所以我已經覆蓋。至於主要問題,我根本不買。代碼的任何單一問題意味着它將無法工作。所以代碼有多個缺陷。如果一個答案不能確定每一個問題,那麼它是否值得一次downvote?這個非常明顯的結論是,需要Pascal轉換。無需對破損的代碼進行過度分析。 – 2012-02-17 13:04:30