วิธีการแปลงไบต์อาร์เรย์เป็นตัวแทนฐานสิบหกใน Delphi

ฉันมีตัวแปร TBytes ที่มีค่า [0,0,15,15] ฉันจะแปลงเป็น "00FF" ได้อย่างไร?

ฉันไม่ต้องการใช้ลูป เพราะตรรกะนี้จะถูกใช้ในฟังก์ชันที่เน้นเวลา

(ฉันลองใช้ BinToHex แต่ฉันไม่สามารถทำงานกับตัวแปรสตริงได้)

ขอขอบคุณและขอแสดงความนับถือ,

ปาวัน.


person Pavan    schedule 29.06.2009    source แหล่งที่มา


คำตอบ (4)


// Swapping is necessary because x86 is little-endian.
function Swap32(value: Integer): Integer;
asm
  bswap eax
end;

function FourBytesToHex(const bytes: TBytes): string;
var
  IntBytes: PInteger;
  FullResult: string;
begin
  Assert(Length(bytes) = SizeOf(IntBytes^));
  IntBytes := PInteger(bytes);
  FullResult := IntToHex(Swap32(IntBytes^), 8);
  Result := FullResult[2] + FullResult[4] + FullResult[6] + FullResult[8];
end;

หากบรรทัดสุดท้ายดูแปลกๆ เล็กน้อย อาจเป็นเพราะคุณร้องขอให้เปลี่ยนอาร์เรย์สี่ไบต์เป็นสตริงสี่อักขระ ในขณะที่ในกรณีทั่วไป ต้องใช้เลขฐานสิบหก แปด หลักเพื่อแสดงอักขระสี่ตัว ค่าไบต์ ฉันแค่สันนิษฐานว่าค่าไบต์ของคุณทั้งหมดต่ำกว่า 16 ดังนั้นจึงต้องใช้เลขฐานสิบหกเพียงหลักเดียวเท่านั้น หากตัวอย่างของคุณพิมพ์ผิด เพียงแทนที่สองบรรทัดสุดท้ายด้วยบรรทัดนี้:

Result := IntToHex(Swap32(IntBytes^), 8);

อย่างไรก็ตาม คุณจะไม่สามารถปฏิบัติตามข้อกำหนดในการห้ามลูปได้ IntToHex ใช้การวนซ้ำภายใน

person Rob Kennedy    schedule 29.06.2009
comment
IntToHex(IntBytes^, 8); สร้างสตริงในลำดับย้อนกลับ หากคุณเห็นคำถามของฉัน ฉันต้องการให้เป็น 00FF แต่ฟังก์ชันด้านบนสร้างเป็น FF00 .. ฉันสามารถระบุลำดับไบต์ได้หรือไม่ - person Pavan; 30.06.2009
comment
ผลลัพธ์ := ผลเต็ม[8] + ผลเต็ม[6] + ผลเต็ม[4] + ผลเต็ม[2]; - person Nosredna; 30.06.2009
comment
มีวิธีใดในการระบุลำดับไบต์แทนที่จะเข้าถึงทีละองค์ประกอบ..?? - person Pavan; 30.06.2009
comment
ขอโทษ. ฉันลืมไปว่า x86 เป็น little-endian ดังนั้นคุณต้องสลับลำดับไบต์ - person Rob Kennedy; 30.06.2009
comment
@Pavan: คุณไม่สามารถเพิ่มพารามิเตอร์ลำดับไบต์บูลีนลงในส่วนหัวของฟังก์ชันได้หรือไม่ จากนั้นใช้บรรทัดสุดท้ายจากคำตอบดั้งเดิมของ Rob และความคิดเห็นของ Nosredna เป็นทางเลือกในคำสั่ง if - person Argalatyr; 30.06.2009

อันนี้ค่อนข้างเร็วและใช้ได้กับอาเรย์ทุกขนาด .. มันเหมือนกับ BinToHex แต่แทนที่จะคาดหวังค่า 0..255 ไบต์กลับใช้แค่แทะต่ำเท่านั้น

procedure BinToSingleHex(Buffer, Text: PAnsiChar; BufSize: Integer);
const
  Convert: array[0..15] of AnsiChar = '0123456789ABCDEF';
var
  I: Integer;
begin
  for I := 0 to BufSize - 1 do
  begin
    Text[0] := Convert[Byte(Buffer[I]) and $F];
    Inc(Text);
  end;
end;

แอสเซมเบลอร์ที่ทำเช่นเดียวกัน:

procedure BinToSingleHex(Buffer, Text: PAnsiChar; BufSize: Integer);assembler;
asm
        PUSH    ESI
        PUSH    EDI
        MOV     ESI,EAX
        MOV     EDI,EDX
        MOV     EDX,0
        JMP     @@1
@@0:    DB      '0123456789ABCDEF'
@@1:    LODSB
        AND     DL,AL
        AND     DL,0FH
        MOV     AL,@@0.Byte[EDX]
        STOSB
        DEC     ECX
        JNE     @@1
        POP     EDI
        POP     ESI
end;

การใช้งาน:

type  THexDigit=0..15;
const ArSize=16;
var   Ar:array[0..Pred(ArSize)] of THexDigit=(0,1,2,3,4,5,6,7,8,9,8,7,6,5,4,3);
      S:Array[0..Pred(ArSize)] of AnsiChar;

BinToSingleHex(@Ar,S,Length(Ar));
WriteLn(S);
person Wouter van Nifterick    schedule 29.06.2009
comment
ระวัง. สตริงผลลัพธ์ของคุณไม่ได้สิ้นสุดด้วยค่า null นอกจากนี้ รหัสของคุณจะต้องปิดการใช้งานคำสั่งคอมไพเลอร์ตัวดำเนินการ @ ที่พิมพ์ เนื่องจากคุณส่งตัวชี้ไบต์ไปยังพารามิเตอร์ที่คาดว่าจะมีตัวชี้ AnsiChar ดีกว่าที่จะเปลี่ยนประเภทของพารามิเตอร์แรกเป็น PByte และคุณจะคิดได้อย่างไรว่าคุณจำเป็นต้องใช้และล้างสี่บิตบนใน Delphi แต่คุณไม่จำเป็นต้องทำในแอสเซมเบลอร์ - person Rob Kennedy; 30.06.2009
comment
คะแนนที่ดี.. และใช่แล้ว คุณพูดถูก.. แน่นอนว่ามันยังจำเป็นต้องปกปิด 4 บิตที่สำคัญที่สุดที่นั่น แก้ไขสิ่งนั้น - person Wouter van Nifterick; 30.06.2009

ไปงานปาร์ตี้สายไปสักหน่อย แต่ทำไมไม่ลองตารางค้นหาแบบธรรมดาดูล่ะ

const
HexChars : Array[0..15] of Char = ('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');

สมมติว่าค่า TBytes เท่ากับ 0..15

Function (ABytea: TBytes): string
    begin 
      Result  := HexChars[ABytea[0]];
      Result  := Result + HexChars[ABytea[1]];
      Result  := Result + HexChars[ABytea[2]];
      Result  := Result + HexChars[ABytea[3]];
    end;

แน่นอนว่าเรียบร้อยกว่าด้วยการวนซ้ำ :) และจำเป็นต้องแก้ไขค่าไบต์ที่สูงกว่า 15:

begin 
  Result  := HexChars[ABytea[0] shr 4];
  Result  := Result + HexChars[ABytea[0] and $0F];
  Result  := Result + HexChars[ABytea[1] shr 4];
  Result  := Result + HexChars[ABytea[1] and $0F];
  Result  := Result + HexChars[ABytea[2] shr 4];
  Result  := Result + HexChars[ABytea[2] and $0F];
  Result  := Result + HexChars[ABytea[3] shr 4];
  Result  := Result + HexChars[ABytea[3] and $0F];
end;

ยังคงเรียบร้อยกว่าด้วยการวนซ้ำโดยเฉพาะอย่างยิ่งหาก TBytes มีขนาดใหญ่ขึ้น

person Despatcher    schedule 02.07.2009

person    schedule
comment
มันคือ TBytes ไม่ใช่ไบต์เดียว .. และฉันไม่ต้องการใช้ลูปเพื่อคำนวณแต่ละค่า ถ้าฉันจำไม่ผิด ตรรกะของคุณใช้งานได้ต่อไบต์ - person Pavan; 30.06.2009
comment
นี่ดูเหมือนเป็นทางออกที่ดีที่สุดที่คุณจะได้รับ คุณจะต้องใช้การวนซ้ำที่ไหนสักแห่ง หากคุณต้องการใช้บน TBytes ให้รวมสิ่งนี้ไว้ในฟังก์ชันที่รับ TBytes และวนซ้ำ สร้างสตริงเอาต์พุตทีละไบต์ - person Mason Wheeler; 30.06.2009
comment
สิ่งนี้สามารถปรับให้เข้ากับโซลูชันแบบไม่มีการวนซ้ำได้ หากคุณใส่ใจกับข้อกำหนดนั้นจริงๆ - person Nosredna; 30.06.2009