2012-03-15 8 views
6

Me gustaría saber cómo declaro un registro, que tiene algunos valores fijos. Necesito enviar datos usando este patrón: Byte($FF)-Byte(0..250)-Byte(0..250). Estoy usando record para eso y me gustaría tener el primer valor constante, para que no se pueda estropear. Tales como:¿Cómo declarar un valor fijo en un registro?

TPacket = record 
    InitByte: byte; // =255, constant 
    FirstVal, 
    SecondVal: byte; 
end; 
+3

Se podría recurrir a tipos subrango – OnTheFly

+0

Si todo lo que estamos haciendo es valores de bytes en un TPacket, en lugar me gustaría utilizar RawByteString y simplemente definir constantes con nombre InitByte = 0, FIrstVal = 1, y así sucesivamente. Y me aseguraré de que el valor inicial sea el valor constante correcto al hacerlo en CÓDIGO en mi función PacketBuild. –

+1

¿Qué versión de Delphi usará? – kobik

Respuesta

12

No se puede confiar en un constructor, ya que, al contrario de las clases, los registros no están obligados a usarlos, el constructor sin parámetros por defecto que se utiliza de forma implícita.

Pero se puede utilizar un campo constante:

type 
    TPacket = record 
    type 
    TBytish = 0..250; 
    const 
    InitByte : Byte = 255; 
    var 
    FirstVal, 
    SecondVal: TBytish; 
    end; 

A continuación, utilice esto como un registro regular, excepto que usted no tiene (y no se puede) cambiar el campo InitByte.
FillChar conserva el campo constante y se comporta como se esperaba.

procedure TForm2.FormCreate(Sender: TObject); 
var 
    r: TPacket; 
begin 
    FillChar(r, SizeOf(r), #0); 
    ShowMessage(Format('InitByte = %d, FirstVal = %d, SecondVal = %d', [r.InitByte, r.FirstVal,r.SecondVal])); 
    // r.InitByte := 42; // not allowed by compiler 
    // r.FirstVal := 251; // not allowed by compiler 
    r.FirstVal := 1; 
    r.SecondVal := 2; 
    ShowMessage(Format('InitByte = %d, FirstVal = %d, SecondVal = %d', [r.InitByte, r.FirstVal,r.SecondVal])); 
end; 

Actualizado para incluir el alcance tipo anidado 0..250

+1

Impresionante. Primera respuesta real. –

+0

@Mike, casi lo es. François, te estás perdiendo el rango de 'FirstVal' y' SecondVal'. Si lo hago bien, deberían estar en el rango de '0..250'. Pero luego puede resolver el problema con 'FillChar', que puede establecer los valores fuera de estos límites (sin duda, la comprobación de rango). – TLama

+1

@TLama, estaba confiando en la declaración de registro del OP y me perdí el alcance. Respuesta actualizada con un subtipo ... –

2

Las versiones modernas de Delphi permiten métodos de registro. Aunque no se puede evitar que alguien cambie el campo al menos puede inicializar correctamente:

type 
    TPacket = record 
    InitByte: byte; // =255, constant 
    FirstVal, 
    SecondVal: byte; 
    constructor Create(val1, val2 : byte); 
    end; 


constructor TPacket.Create(val1, val2: byte); 
begin 
    InitByte := 255; 
    FirstVal := val1; 
    SecondVal := val2; 
end; 
+1

Desafortunadamente, no se puede exigir el uso del constructor ... –

0

Teniendo en cuenta el hecho de que los registros pueden ahora tener propiedades, puede definir un registro como:

TMixedFixed = record 
strict private 
    FFixed: byte; 
    FVariable1: byte; 
    FVariable2: byte; 
public 
    property Fixed read FFixed; 
    property Variable read FVariable write FVariable; 
    constructor Create(Var1, Var2: byte); 
end; 

constructor TMixedFixed.create(Var1, Var2: byte); 
begin 
    FFixed:= 255; 
    FVariable1:= Var1; 
    FVariable2:= Var2; 
end; 

Dado el hecho de que las variables reales son estrictamente privadas, no debería poder tocarlas sin magia especial. Sin embargo, deberá usar el constructor para iniciar los valores 'fijos'.

+0

No impide declarar una variable y usarla como un registro estándar sin usar el constructor Simplemente tendrá basura en 'FFixed' y no habrá manera de cambiarla ... –

+0

@ François, ¿no puede anular el constructor predeterminado? – Johan

+0

no que yo sepa. El constructor predeterminado es tan prominente que incluso le impide declarar otro constructor sin parámetros. Cualquier constructor personalizado que proporciones debe tener parámetros. Ver [docwiki] (http://docwiki.embarcadero.com/RADStudio/es/Structured_Types): "Los registros se construyen automáticamente, utilizando un constructor predeterminado sin argumento, pero las clases deben construirse explícitamente. Porque los registros tienen un valor predeterminado no- constructor de argumento, cualquier constructor de registro definido por el usuario debe tener uno o más parámetros ". –

0

Ésta es la forma más sencilla:

type 
    TPacket = record 
    InitByte: byte; // =255, constant 
    FirstVal, 
    SecondVal: byte; 
    end; 

var 
    Packet : TPacket = (InitByte: 255); 

const 
    Packet1 : TPacket = (InitByte: 255); 
+1

No, no es la única manera, ver mi respuesta.Y, por cierto, no puede inicializar variables locales como su variable de paquete (error de compilación E2195). –

Cuestiones relacionadas