ボイド型パラメーターの読み取りと割り当て
-
11-09-2019 - |
質問
ボイド型パラメーターを使用して2つの方法を書きました。
procedure Method1(const MyVar; size: cardinal);
var
Arr: array of byte;
begin
SetLength(Arr, size);
{now copy the data from MyVar to Arr, but how?}
end;
procedure Method2(var MyVar; size: cardinal);
var
Arr: array of byte;
begin
SetLength(Arr, size);
{return the data from the array, but how?}
end;
最初のものでは、バイトの配列としてmyvarにアクセスしたいと思います。 2番目では、ローカルアレイARRからMyVarにデータをコピーしたいと思います。したがって、私はcopymemory()関数を使用しましたが、何かが間違っています。
2番目の方法で以下を使用する場合、メソッド2がそのパラメーター(Method2(myString)^、length(mystring))またはmethod2(pointer(myarray)、length(myarray)として配列と呼ばれる限り、それは問題ありません))。
CopyMemory(Pointer(MyVar), Pointer(Arr), size);
たとえば、integerパラメーター(method2(myinteger、sizeg(myinteger)))でaをaで呼び出すと、正しく動作しません。この場合、このように呼び出す必要があります。
CopyMemory(@MyVar, Pointer(Arr), size);
Method2からデータを正しく返す方法は、それが単純なタイプ(またはレコード)か配列かを知らないのですか? Method1で状況は似ていますが、ここで使用する必要があります
CopyMemory(Pointer(Arr), Pointer(MyVar), size);
配列の場合と
CopyMemory(Pointer(Arr), @MyVar, size);
単純なタイプの場合。
myvarパラメーターが何であるかわからないとき、私はそれについて何ができますか?
解決
Delphiにはそのようなことはありません。あなたが言及しているものはanと呼ばれます Untypedパラメーター.
無型のパラメーターは常にです 実際のもの自体, 、あなたが使用することになっているものへのポインターではありません。したがって、使用する正しい方法 CopyMemory
このようなパラメーターを使用すると、を適用します @
そのように、それにオペレーター:
CopyMemory(@MyVar, @Arr[0], size);
また、2番目のパラメーターを渡す方法を変更したことに注意してください。ダイナミックアレイが実際に最初の要素へのポインターであるという事実に依存しない場合は、より良いことです。最初の要素へのポインターが必要な場合は、ここで行ったように、明確に言ってください。
あなたの混乱は、パラメーターがポインターであるかのように使用された場所で作成したテストから生じ、テストは機能しているように見えました。ただし、そのテストの妥当性は疑わしいです。あなたが言ったとき Pointer(MyString)^
, 、あなたが持っていたのは、文字列の最初のキャラクターでした。あなたが言ったとき Pointer(MyVar)
関数の内部では、そのキャラクターをタイプキャストしてポインターに入れていました。これは無効なタイプキャストでした。あなたのプログラムが機能しているように見える場合、それは偶然でした。あなたのコードは間違っていました。
私が与えることができる最善のアドバイスは、あなたが本当にしなければならない限り、タイプキャストをしないことです。そして、あなたがそうするとき、あなたがタイプキャストしているものに本当にそのタイプがあることを確認してください。あなたの場合、型のパラメーターとして渡す前に、何もキャストする必要はありません。あなたは電話することができます Method1
このような:
Method1(MyString[1], Length(MyString) * Sizeof(Char));
(乗算します SizeOf(Char)
Delphi 2009を持っているかどうかわからないので。)
また、無型のパラメーターを避けてください。コンパイラがプログラムの正確性を確保するためにできる素晴らしいことの1つは、タイプの安全性を強制することですが、タイプを奪うと、コンパイラはあなたを助けることができません。
他のヒント
問題は、データまたはポインターのいずれかをMethod1/2に渡すことです。常にデータ自体を渡す必要があります。ダイナミックアレイがポインター自体であることを忘れただけかもしれません。メソッドにaまたはポインター(a)を渡さないでください(aはここで動的な配列です)。 [0]またはポインター(a)^を渡します。
procedure Method1(const MyVar; size: cardinal);
var
Arr: array of byte;
begin
SetLength(Arr, size);
CopyMemory(Pointer(Arr), @MyVar, Size);
end;
procedure Method2(var MyVar; size: cardinal);
var
Arr: array of byte;
begin
SetLength(Arr, size);
Arr[0] := 1;
Arr[1] := 2;
Arr[2] := 3;
Arr[3] := 4;
CopyMemory(@MyVar, Pointer(Arr), Size);
end;
procedure TForm1.FormCreate(Sender: TObject);
var
I: Integer;
A: array of Integer;
begin
I := $01020304;
Method1(I, 4); // we pass data itself, not the pointer to it.
Method2(I, 4);
SetLength(A, 2);
A[0] := 0;
A[1] := $01020304;
Method1(A[0], Length(A) * SizeOf(A[0])); // note, that we pass data, not pointer
Method2(A[0], Length(A) * SizeOf(A[0])); // A or Pointer(A) is a pointer to array's data
end;
Aが動的配列の場合:
- a [0]はpointer(a)^と同じであり、配列のデータを表します。
- @a [0]は、ポインター(a)またはAのみと同じであり、配列自体を表します。これは、そのデータへのポインターです(およびネガティブオフセットに関する技術情報)。
aが静的配列の場合:
- a [0]はaと同じであり、配列自体を表します。これは配列のデータです。
- @a [0]は@aと同じであり、配列へのポインターを表します。
- ポインター(a)またはポインター(a)^は無意味です。
Arr in method1/2は動的な配列でもあるため、ポインターにキャストする理由です(Copymemoryはデータではなくポインターを尋ねます)。移動ルーチン(データを要求する)を使用する場合は、代わりにポインター(a)^を記述する必要があります。