php小編西瓜在這裡為大家介紹一下Go和C的資料結構對齊差異。在程式語言中,資料結構對齊是為了提高記憶體存取效率而進行的一種記憶體對齊方式。然而,Go和C在資料結構對齊方面存在一些差異。在C語言中,對齊是透過編譯器的設定來控制的,而在Go語言中,對齊則是由編譯器自動完成的。這種差異可能會導致使用C語言編寫的程式碼在Go語言中出現記憶體存取錯誤。因此,了解Go和C中的資料結構對齊差異對於開發人員來說是非常重要的。
我已經在我的 C 程式中初始化了一個結構並將其附加到共享記憶體。結構如下:
#define DrvMaxTag 1024 #define DrvMaxStr 128 #define StructLEN 32 typedef struct TagTypeStruct { unsigned char IO; unsigned char Drv; unsigned char Class; unsigned char Group; }TagTypeStruct; typedef struct IEC_DT { long int tv_Sec; long int tv_nSec; }IEC_DT; typedef struct DrvSHMTagStruct { char TagName[DrvMaxTag][DrvMaxStr]; double TagValue[DrvMaxTag]; double OldValue[DrvMaxTag]; unsigned int TagStatus[DrvMaxTag]; unsigned int OldStatus[DrvMaxTag]; long long TagControl[DrvMaxTag]; IEC_DT TagValueDT[DrvMaxTag]; TagTypeStruct TagType[DrvMaxTag]; int DrvAddr[DrvMaxTag]; unsigned char LogFlag[DrvMaxTag]; unsigned char Freeze[DrvMaxTag]; int LogicState; char DrvPath[DrvMaxStr]; int TagQuantity; unsigned char Instance; }DrvSHMTagStruct;
我正在嘗試從另一個用 Golang 編寫的程式中讀取結構。我計算了 C 中每個字段佔用的位元組數,並在我的 Golang 結構中擁有一個等效字段,如下所示:
const StructLEN = 32 const DrvMaxTag = 1024 const DrvMaxStr = 128 type TagTypeStruct struct { IO uint8 Drv uint8 Class uint8 Group uint8 } type IEC_DT struct { tv_Sec int32 tv_nSec int32 } type DrvSHMTagStruct struct { TagName [DrvMaxTag][DrvMaxStr]byte TagValue [DrvMaxTag]float64 OldValue [DrvMaxTag]float64 TagStatus [DrvMaxTag]uint32 OldStatus [DrvMaxTag]uint32 TagControl [DrvMaxTag]int64 TagValueDT [DrvMaxTag]IEC_DT TagType [DrvMaxTag]TagTypeStruct DrvAddr [DrvMaxTag]int32 RetainFlag [DrvMaxTag]uint8 Freeze [DrvMaxTag]uint8 LogicState int32 DrvPath [DrvMaxStr]uint8 TagQuantity int32 Instance uint8 }
結構體(DrvSHMTagStruct
)的大小在C中是182416,在Golang中是182412(我的作業系統是基於ARM的)。那為什麼會有這樣的差異呢?它們有 4 個位元組不同,有趣的是它們都工作得很好,在相同的結構上讀寫,沒有錯誤。
正如我顯然搜尋過的那樣,我了解到 C 編譯器在編譯過程中會進行一些資料結構對齊。因此,有 4 個位元組的差異。但問題是,即使有 4 個位元組的差異,Golang 程式如何正確地從共享記憶體讀取結構呢?
此外,當我在基於 ARM 的 Linux 上執行程式時,問題出現了。它們在 x64 Ubuntu 上的大小相同。
這是最後一個成員Instance
的填滿。在你的 C 版本中,它用 7 個位元組填充。在 Go 版本中,它用 3 填充。差別在於您在兩個平台上執行sizeof
時注意到的 4 個位元組。
為了讓它們相同,您可以在C 版本中使用#pragma pack(4)
或在Go 版本中使用#pragma pack(8)
(如果它甚至支持打包,搜尋建議它沒有)或添加一個填充符作為Go 結構的最後一個成員:
Filler1 [7]uint8
以上是Go和C中的資料結構對齊差異的詳細內容。更多資訊請關注PHP中文網其他相關文章!