2014-05-09 11 views
7

Sto convertendo un'intestazione C per un'unità di delphi. Ho dei dubbi sull'UNION. Ad esempio, negli esempi seguenti, qual è la logica applicata in (CASE INTEGER OF)? È questo il modo corretto per convertire questa struttura?Converti struttura da C a Delphi

In C

typedef union _FLT_PARAMETERS { 

    struct { 
     PIO_SECURITY_CONTEXT SecurityContext; 
     ULONG Options; 
     USHORT POINTER_ALIGNMENT FileAttributes; 
     USHORT ShareAccess; 
     ULONG POINTER_ALIGNMENT EaLength; 
     PVOID EaBuffer;     
     LARGE_INTEGER AllocationSize; 
    } Create; 

    struct { 
     PIO_SECURITY_CONTEXT SecurityContext; 
     ULONG Options; 
     USHORT POINTER_ALIGNMENT Reserved; 
     USHORT ShareAccess; 
     PVOID Parameters; // PNAMED_PIPE_CREATE_PARAMETERS 
    } CreatePipe; 

    ... 

In Delphi

TCreate = record 
     SecurityContext: PIO_SECURITY_CONTEXT; 
     Options: ULONG; 
     FileAttributes: USHORT; 
     ShareAccess: USHORT; 
     EaLength: ULONG; 
     EaBuffer: PVOID;     
     AllocationSize: LARGE_INTEGER; 
    end; 

    TCreatePipe = Record 
     SecurityContext: PIO_SECURITY_CONTEXT; 
     Options: ULONG; 
     Reserved: USHORT; 
     ShareAccess: USHORT; 
     Parameters: PVOID; 
    end;  

    _FLT_PARAMETERS = Record 
    case integer of 
     0: (Create: TCreate); 
     1: (CreatePipe: TCreatePipe): 
    ... 

risposta

4

È questo il modo corretto per convertire tale struttura?

L'unione è correttamente tradotta. Il tuo record di varianti Pascal è il modo corretto di gestire l'unione. La parte variante di un record è trattata in modo identico a un sindacato C. Da documentation:

I record con parti varianti sono sintatticamente complicati ma ingannevolmente semplici semanticamente. La parte variante di un record contiene diverse varianti che condividono lo stesso spazio in memoria. Puoi leggere o scrivere in qualsiasi campo di qualsiasi variante in qualsiasi momento; ma se scrivi su un campo in una variante e poi su un campo in un'altra variante, potresti sovrascrivere i tuoi dati.


L'unico problema che posso vedere con il codice è la macro POINTER_ALIGNMENT. A cosa si espande questa macro? La mia aspettativa è che si espanderà a __declspec(align(4)) per il codice a 32 bit e __declspec(align(8)) per il codice a 64 bit.

Supponendo che l'ipotesi sia corretta, il codice Delphi avrà già il layout corretto durante la compilazione per 32 bit. Questo perché ogni campo contrassegnato con POINTER_ALIGNMENT sarà già posizionato su un limite di 4 byte.

Ma il record non verrà impostato correttamente per 64 bit. Se stai puntando a 64 bit, dovrai aggiungere del padding extra perché ogni membro contrassegnato con POINTER_ALIGNMENT verrà impostato in modo errato. Sfortunatamente non esiste un equivalente in Delphi a __declspec(align(#)) quindi è necessario aggiungere manualmente il padding.

Se è necessario aggiungere questo padding, è necessario controllare molto attentamente che entrambe le versioni C e Delphi abbiano lo stesso layout. Controlla che gli offset per ogni campo corrispondano.

+1

Ciò che non mi è chiaro è come il sistema sceglie l'opzione nel caso. A quanto ho capito, è come se avessi un tipo VARIANT che può essere TCreate o TCreatePipe. questo è corretto? – Flz

+1

Capisci come funziona un sindacato? La parte variante di un record è identica. Ho incluso un link alla documentazione e un estratto. Sarebbe davvero di grande aiuto se mi mostrassi cosa significa "POINTER_ALIGNMENT" in modo da non dover indovinare. –