Search code examples
cgodata-structuresshared-memory

Data structure alignment difference in Go and C


I have initialized a structure inside my C program and attached it to the Shared memory. The structure is as below:

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

I'm trying to read the structure from another program that is written in Golang. I have calculated how many bytes each field takes in C and have an equivalent field for it inside my Golang structure which is as below:

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
}

The size of the structure (DrvSHMTagStruct) in C is 182416 and in Golang is 182412 (my OS is ARM-based). So why the difference? They are different in 4 bytes and the interesting part is that they are both working perfectly, reading and writing on the same structure without a mistake.

As I obviously searched about it, I understood that the C compiler does some Data Structure alignment during the compilation process. Hence, the 4 bytes difference. But the question is how does the Golang program read the structure from the shared memory correctly even though it has a 4-byte difference?

Also, the problem emerges when I run the programs on my ARM-based Linux. They are the same size when on a x64 Ubuntu.


Solution

  • It's the padding of the last member, Instance. In your C version, it gets padded with 7 bytes. In the Go version it gets padded with 3. The difference is the 4 bytes you notice when doing sizeof on the two platforms.

    In order to make them the same, you can possibly #pragma pack(4) in the the C version or #pragma pack(8) in the Go version (if it even supports packing, a search suggests that it doesn't) or add a filler as a last member to the Go struct:

    Filler1     [7]uint8