2014-05-09 95 views
7

我爲一個delphi單元轉換一個C頭。我對聯盟有懷疑。 例如,在下面的例子中,應用於(CASE INTEGER OF)的邏輯是什麼? 這是轉換此結構的正確方法嗎?將結構從C轉換爲Delphi

在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; 

    ... 

在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): 
    ... 

回答

4

這是這種結構轉換的正確方法是什麼?

該聯合會被正確翻譯。您的Pascal變體記錄是處理工會的正確方法。記錄的變體部分與C union的處理方式相同。來自documentation

變體部分的記錄在語法上是複雜的,但在語義上很複雜。記錄的變體部分包含多個在內存中共享相同空間的變體。您可以隨時閱讀或寫入任何變體的任何字段;但是如果你在一個變體中寫入字段,然後寫入另一個變體中的字段,則可能會覆蓋自己的數據。


我可以用你的代碼中看到的唯一的問題是宏觀POINTER_ALIGNMENT。這個宏是什麼擴展到?我的期望是它將擴展到__declspec(align(4)) 32位代碼和__declspec(align(8)) 64位代碼。

假設猜測是正確的,在編譯32位時,你的Delphi代碼已經具有正確的佈局。這是因爲標有POINTER_ALIGNMENT的每個字段都將被放置在4字節的邊界上。

但是該記錄不會正確地爲64位佈局。如果你的目標是64位,你將不得不添加一些額外的填充,因爲標記爲POINTER_ALIGNMENT的每個成員將被錯誤地佈置。不幸的是,在Delphi中沒有相應的__declspec(align(#)),因此您需要手動添加填充。

如果您確實需要添加這個填充,您應該仔細檢查C和Delphi版本是否具有相同的佈局。檢查每個字段的偏移量是否匹配。

+1

我不清楚的是系統如何選擇案件中的選項。據我瞭解,就好像我有一個可以是TCreate或TCreatePipe的VARIANT類型。這是對的? – Flz

+1

你瞭解工會的工作原理嗎?記錄的變體部分是相同的。我已經包含了文檔鏈接和摘錄。如果你向我展示了什麼'POINTER_ALIGNMENT',這也是非常有用的,所以我不必猜測。 –