Pregunta

escribí dos métodos con un parámetro de tipo de vacío:

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;

En el primero me gustaría tener acceso a la MiVar como una matriz de bytes. En la segunda, me gustaría copiar los datos de la matriz local Arr a MiVar. Por lo tanto, he utilizado la función CopyMemory (), pero algo está mal con él.

Si utilizo el siguiente en el segundo método, es bien siempre que se llama Método 2 con una matriz como su parámetro (Método 2 (Puntero (MyString) ^, Longitud (MyString)) o Método 2 (Puntero (MiArray), Longitud (MiArray))).

CopyMemory(Pointer(MyVar), Pointer(Arr), size);

Si llamo Método2 con, por ejemplo, parámetro entero (Método 2 (MiEntero, sizeof (MiEntero))), que no funciona correctamente. En este caso, el CopyMemory () tiene que ser llamado de esta manera:

CopyMemory(@MyVar, Pointer(Arr), size);

Cómo devolver datos de Método2 correctamente sin saber si se trata de un tipo simple (o registro) o una matriz? La situación será similar en Método1, pero aquí me tendría que utilizar

CopyMemory(Pointer(Arr), Pointer(MyVar), size);

en el caso de matrices y

CopyMemory(Pointer(Arr), @MyVar, size);

en el caso de los tipos simples.

¿Qué puedo hacer al respecto cuando no sé lo que es el parámetro MiVar?

¿Fue útil?

Solución

No hay tal cosa que un tipo vacío en Delphi. Lo que usted se refiere se llama una parámetro sin tipo .

Un parámetro sin tipo es siempre el cosa en sí , no un puntero a lo que se supone que utilice. Por lo tanto, la forma correcta de utilizar CopyMemory con un parámetro tal es aplicar el operador @ a ella, así:

CopyMemory(@MyVar, @Arr[0], size);

Note que también he cambiado la forma en que paso por el segundo parámetro. Es mejor si no se basan en el hecho de que una matriz dinámica es realmente un puntero al primer elemento. Si necesita un puntero al primer elemento, simplemente decirlo explícitamente, como lo hice aquí.

Su confusión proviene de una prueba que hizo que se utilizó el parámetro como si se tratara de un puntero, y la prueba parecía funcionar. Dudo que la validez de la prueba, sin embargo. Cuando dijo Pointer(MyString)^, lo que tenía era el primer carácter de la cadena. Cuando a continuación, dijo Pointer(MyVar) dentro de la función, que eras el tipo de fundición a ese personaje en un puntero, que era un tipo de difusión no válida. Si su programa parecía funcionar, entonces era sólo por accidente; su código estaba mal.

El mejor consejo que puedo dar es que no cosas de tipo fundido a menos que realmente tenga que hacerlo. Y cuando lo hace, por favor asegúrese de que lo que estás tipo de fundición a presión realmente tiene ese tipo. En su caso, usted no tiene que escribir fundido a nada antes de pasarlo como un parámetro sin tipo. Puede llamar Method1 como esto:

Method1(MyString[1], Length(MyString) * Sizeof(Char));

(multiplico por SizeOf(Char) ya que no sabe si tiene Delphi 2009 o no.)

Además, ¿evitar parámetros sin tipo. Una de las grandes cosas que un compilador puede hacer para ayudar a asegurar la corrección del programa es hacer cumplir la seguridad de tipos, pero cuando se quita los tipos, el compilador no puede ayudar más.

Otros consejos

Su problema es que se pasa de datos o un puntero a los datos a Método1 / 2. Siempre debe pasar los datos en sí. Puede ser simplemente te olvidaste de matriz dinámica que es un puntero a sí misma? No se debe pasar un puntero o (A) en sus métodos (A es matriz dinámica aquí). Pasar A [0] o puntero (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;

Si A es matriz dinámica:

  1. A [0] es el mismo que Puntero (A) ^ y representa los datos de la matriz.
  2. @A [0] es el mismo que el puntero (A) o simplemente A y representa la matriz en sí, que es puntero a los datos de TI (y algo de información sobre tecnología desplazamientos negativos).

Si A es matriz estática:

  1. A [0] es el mismo que A y representa la matriz en sí, que son datos de la matriz.
  2. @A [0] es el mismo que @A y representa el puntero al array.
  3. Pointer (A) o puntero (A) ^ no tienen sentido.

Tenga en cuenta, que en Arr Método1 / 2 es una matriz dinámica también, es por eso que echarlo a puntero (CopyMemory pide punteros, no los datos). Si queremos utilizar rutina de movimiento (que pide datos), debemos escribir Puntero (A) ^ su lugar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top