[英]How to pass dynamic array as untyped 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.