簡體   English   中英

如何將動態數組作為無類型的const傳遞?

[英]How to pass dynamic array as untyped const?

我正在調用一個函數:

  • 無類型的const
  • 字節長度

這是一種常見的Delphi模式。 例如:

procedure DoStuff(const Data; DataLen: Integer);

在這個示例測試用例中,所有DoStuff都會確保它收到四個字節:

0x21 0x43  0x65  0x87

出於測試目的,我們將在我們的小端Intel機器上將該字節序列解釋為32位無符號整數: 0x87654321 這使得完整的測試功能:

procedure DoStuff(const Data; DataLen: Integer);
var
    pba: PByteArray;
    plw: PLongWord;
begin
    //Interpret data as Longword (unsigned 32-bit)
    plw := PLongWord(@Data);
    if plw^ <> $87654321 then
        raise Exception.Create('Fail');

    //Interpret data as array of bytes
    pba := PByteArray(@Data);
    if (pba[0] <> $21) or (pba[1] <> $43) or (pba[2] <> $65) or (pba[3] <> $87) then
        raise Exception.Create('Fail');

//  ShowMessage('Success');
end;

出於說明目的,已經闡明了錯誤檢查。

測試

我可以開始測試我可以正確地將字節傳遞給我的DoStuff函數。

//Pass four bytes in a LongWord
var lw: LongWord;
lw := $87654321;
DoStuff(lw, 4); //works

因此,將LongWord傳遞給采用無類型const的函數的方法是傳遞變量。 即:

  • 錯了@lw
  • 錯了Addr(lw)
  • Pointer(@lw)^
  • 正確lw

我也可以傳遞一個8字節的類型; 因為我只讀了前四個字節:

//Pass four bytes in QuadWord
var qw: Int64;
qw := $7FFFFFFF87654321;
DoStuff(qw, 4); //works

數組

現在我們得到一些更棘手的東西:傳遞數組:

//Pass four bytes in an array
var data: array[0..3] of Byte;
data[0] := $21;
data[1] := $43;
data[2] := $65;
data[3] := $87;
DoStuff(data[0], 4); //Works

//Pass four bytes in a dynamic array
var moreData: TBytes;
SetLength(moreData, 4);
moreData[0] := $21;
moreData[1] := $43;
moreData[2] := $65;
moreData[3] := $87;
DoStuff(moreData[0], 4); //works

這些都正常工作。 但在你們有些人猶豫之前,讓我們來看看更棘手的案例:

//Pass four bytes at some point in an array
var data: array[0..5] of Byte;
data[2] := $21;
data[3] := $43;
data[4] := $65;
data[5] := $87;
DoStuff(data[2], 4); //Works

//Pass four bytes at some point in a dynamic array
var moreData: TBytes;
SetLength(moreData, 6);
moreData[2] := $21;
moreData[3] := $43;
moreData[4] := $65;
moreData[5] := $87;
DoStuff(moreData[2], 4); //works

因為untyped const運算符通過引用隱式傳遞,所以我們從數組中的第3個字節開始傳遞引用(並且我們沒有浪費的臨時數組副本)。

從這里我可以推斷出如果我想將一個數組傳遞給一個無類型的const你傳遞一個索引數組的規則:

DoStuff(data[n], ...);

兩個問題

第一個問題是如何將動態數組傳遞給無類型的const函數。 例如:

var
   data: TBytes;
begin
   data := GetData;
   DoStuff(data[0], Length(0));

如果data為空(由於范圍檢查錯誤),此通用代碼將失敗。

另一個問題是對某些語法傳遞data[0]而不是簡單地使用data的批評:

//Pass four bytes in an array without using the array index notation
data[0] := $21;
data[1] := $43;
data[2] := $65;
data[3] := $87;
DoStuff(data, 4); //works

這確實有效。 它確實意味着我失去了以前的能力:傳遞一個索引數組。 但真正的問題是它與動態數組一起使用時會失敗:

//Pass four bytes in a dynamic array without using the array index notation
SetLength(moreData, 4);
moreData[0] := $21;
moreData[1] := $43;
moreData[2] := $65;
moreData[3] := $87;
DoStuff(moreData, 4); //FAILS

問題是有一個如何實現動態數組的內部實現細節。 動態數組實際上是一個指針,而一個數組實際上是一個數組。

這是否意味着如果我傳遞一個數組,我必須弄清楚它是哪種類型,並使用不同的解決方法語法?

//real array
DoStuff(data, 4); //works for real array
DoStuff(data, 4); //fails for dynamic array
DoStuff(Pointer(data)^, 4); //works for dynamic array

這真的是我應該做的嗎? 是不是有更正確的方法?

獎金解決方法

因為我不想失去索引數組的能力:

DoStuff(data[67], 4);

我可以保持索引表示法:

DoStuff(data[0], 4);

並且只需確保處理邊緣情況:

if Length(data) > 0 then
   DoStuff(data[0], 4)
else
   DoStuff(data, 0); //in this case data is dummy variable

所有這一切的全部意義在於不在內存中復制數據; 但要通過引用傳遞它。

這真的很簡單。

DoStuff(data, ...);           // for a fixed length array
DoStuff(Pointer(data)^, ...); // for a dynamic array

是這樣做的正確方法。 動態數組是指向第一個元素的指針,如果數組為空,則為nil

一旦放棄了類型安全並使用無類型參數,在調用這樣的函數時,期望稍微更多的摩擦是合理的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM