对于 c 中的结构,'aligned' 是什么意思?

What does 'aligned' mean, for structs in c?

我正在为在 c api 和 .net 应用程序之间编写一些粘合代码而苦苦挣扎。为了编写 C# 结构,我需要弄清楚 c 端的实际情况。

typedef struct CommonDialogBaseParam {
    size_t size;
    uint8_t reserved[36];
    uint32_t magic;
} CommonDialogBaseParam __attribute__ ((__aligned__(8)));

// Somewhere else
#define __attribute__(x)

我很想按如下方式编写 C# 等价物:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct CommonDialogBaseParam {
    public ulong size;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=36)]
    public string reserved;
    public uint magic;
}

不用说...我真的不需要在 C# 端正确访问 'reserved' 或 'magic',但我需要正确保留成员。

这是一个 GCC 属性,指定结构的最小对齐为 8 字节。可以在此处找到文档:https://gcc.gnu.org/onlinedocs/gcc/Common-Type-Attributes.html#Common-Type-Attributes

这会影响这些结构的分配,但不会影响结构本身的偏移量。但是,这确实意味着本机结构可能在最终成员之后有额外的填充。

在 C# 中没有与此等效的方法,并且根据本机代码对结构的处理,您可能会遇到问题。如果由您的 C# 代码分配,该结构可能会错位,但这只会影响性能而不是正确性。如果本机代码制作了结构的副本,那么它将尝试读取结构末尾的任何填充。可以想象,这可能会导致访问冲突。我的猜测是 p/invoke 使用的堆分配器将以块大小至少为 8 的块为单位分配内存,因此您很可能不会这样做。但我怀疑你能否依赖它。

撇开这个填充,我会这样翻译你的结构:

[StructLayout(LayoutKind.Sequential)]
public struct CommonDialogBaseParam {
    public UIntPtr size;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=36)]
    public byte[] reserved;
    public uint magic;
}

请注意,我已将 size_t 映射到 UIntPtr,一个无符号指针大小的值。就我个人而言,我更喜欢在 reserved 字段中看到 byte[]。据我所知,这对 C 代码来说更真实。

如果你想确保你的结构足够大,那么你可以在末尾添加一个额外的字段:

[StructLayout(LayoutKind.Sequential)]
public struct CommonDialogBaseParam {
    public UIntPtr size;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=36)]
    public byte[] reserved;
    public uint magic;
    private uint padding;
}

由于此结构中包含的 none 类型的大小大于 8,因此您可以滥用 StructLayoutPack 选项来实现所需的效果:

[StructLayout(LayoutKind.Sequential, Pack=8)]
public struct CommonDialogBaseParam {
    public UIntPtr size;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=36)]
    public byte[] reserved;
    public uint magic;
}

但要小心这一点。本机代码对齐结构。上面的 C# 声明对齐结构,并指定其成员的对齐方式。碰巧这里不会影响成员对齐,但情况并非总是如此。

总而言之,有点不尽如人意。