2009-05-18 25 views
5

en C++ se realiza Es así:Cómo asignar un byte [] para un registro

tPacket * packet = (tPacket *)data; //data is byte[] array; tPacket is a structure 

En C#:

tPacket t = new tPacket(); 
GCHandle pin = GCHandle.Alloc(data, GCHandleType.Pinned); 
t = (tPacket)Marshal.PtrToStructure(pin.AddrOfPinnedObject(), typeof(tPacket)); 
pin.free(); 

de datos es una matriz de bytes utilizado como un búfer de recepción después de un paquete se recibe a través de TCP. Ese código pone los datos en una instancia de tPacket (una estructura) para que pueda acceder a la estructura más tarde.

¿Cómo se hace en Delphi?

+0

Espero que su C++ tPacket sea un POD (sin métodos virtuales) y no contenga ningún puntero o refrences. Y espero que su C# tPacket sea un tipo de valor que solo consta de tipos de valores (que solo consta de tipos de valores, ... por lo que no hay ningún tipo de referencia en su gráfico de objetos). – mmmmmmmm

Respuesta

4

Puede también use la palabra clave absoluta para obligar a ambas estructuras a compartir la misma dirección de memoria:

var 
    Data: array[1..SizeOf(TMyStruct)] of byte; 
    s : TMyStruct absolute Data; 

Cualquier dato escrito a S i s también está disponible como Datos sin tener que realizar un movimiento o un lanzamiento de puntero.

+0

Por supuesto, eso NO funcionará, ya que las matrices dinámicas son tipos de referencia. La matriz debe ser no dinámica. –

+0

No declaro los datos como una matriz dinámica. Al llamar a Recv(), los datos tienen un tamaño de 8192 bytes. :) Gracias funcionó. –

+0

Bueno, es bueno que funcionó para ti, pero ¿podría la respuesta ser editada para algo utilizable entonces? Además, el truco definitivo puede ser bueno para casos simples como este, pero la forma idiomática de tener S disponible como Datos sin movimiento o tipo de letra sería usar un registro de variante, similar a una unión en C. – mghie

2

Esto puede ser complicado ya que debe asegurarse de que los diseños de la estructura de origen y de destino sean idénticos. Si es así, entonces usted tiene 2 opciones: o bien utilizar un puntero a la matriz de datos, o utilizar una copia de la memoria:

Puntero:

type 
    // Declare a pointer type for your struct. 
    PMyStruct = TMyStruct^; 

... 

var 
    ptr: PMyStruct; 
begin 
    ptr := PMyStruct(Cardinal(@Data)); 
    // use ptr... 
end; 

copia de la memoria:

var 
    Data: array of Byte; 
    s: TMyStruct; 
begin 
    // fill Data... 
    if SizeOf(s) <> Length(Data) then 
    raise Exception.Create('Input size is not the same size as destination structure.'); 
    CopyMemory(@s, @Data, Length(Data)); 
    // use s... 
end; 
+0

El problema es que en el código C++/C# no es idéntico. La estructura tiene un tamaño de 10 bytes y el tamaño del paquete podría ser de más de 2000 bytes. –

+0

Simplemente use el primer ejemplo, luego, el método del puntero. Es idéntico al código C++. –

+0

Personalmente, escribiría en @data [0], ya que probablemente no desee sobrescribir el valor del puntero. –

3

Puede hacer en Delphi exactamente lo que haría en C++. Sin embargo, defina un tipo con nombre para el puntero de registro, ya que Delphi no le permite definir tipos en los enunciados.

type 
    PPacket = ^TPacket; 
var 
    packet: PPacket; 

packet := PPacket(@data[0]); 
  • La razón por la que he utilizado @data[0] es que funciona independientemente de si los datos es una matriz dinámica. Si se trata de una matriz dinámica, entonces data es realmente un puntero al primer byte del paquete, así que esto funcionaría:

    packet := PPacket(data); // for dynamic array only 
    

    Pero si data se no una matriz dinámica, entonces ese tipo de fundición ganaron' ser valido En su lugar, había necesidad de encasillarse un punteroa data, así:

    packet := PPacket(@data); // for static array only 
    

    Eso no va a funcionar si se trata de una matriz dinámica. El primer código funcionará en ambos casos. Pero si tiene habilitada la comprobación de rango (y probablemente debería hacerlo), entonces creo que el primer código generará una excepción si data es una matriz dinámica de longitud cero, así que tenga cuidado.


Si quieres ir al # ruta C en lugar, donde se copian los bytes de la matriz en un TPacket variable separada, entonces me gustaría usar esto:

var 
    packet: TPacket; 

// Source param comes first. Params are passed by 
// reference automatically. 
Move(data[0], packet, SizeOf(packet)); 

Usted' Necesitaré asegurarme de que data contiene suficientes bytes para completar un valor TPacket completo.TPacket es mejor que no contenga ningún tipo gestionado por el compilador, como string, Variant, IUnknown, o tipos de matriz dinámica. Ni el puntero de tipo fundido ni Move se comportan bien cuando ese es el caso.

Cuestiones relacionadas