简体   繁体   English

如何正确地将 C 结构写入磁盘上的文件,以便可以在其上使用 mmap?

[英]How to properly write C structure to file on disk, so it was possible to use mmap on it?

I use following C structure in memory:我在 memory 中使用以下 C 结构:

typedef struct MyStructHdr
{

    char        text[4];
    int         version_num;

    uint64 init_value;

    uint64 entries[];

} MyStructHdr;

typedef MyStructHdr *MyStruct;

Field entries[] is a pointer to some flexible array. Field entries[]是指向某个灵活数组的指针。 Type uint64 is a custom portable application specific type, which add uint64_t support on 32-bit OS.类型uint64是一种自定义的可移植应用程序特定类型,它在 32 位操作系统上添加了uint64_t支持。

I have to properly write this structure to file, so that I was able to use mmap() on it later (on the same platform/OS):我必须正确地将此结构写入文件,以便以后能够在其上使用mmap() (在同一平台/操作系统上):

map = (MyStruct) mmap(NULL, MyStructActualSize,
                      PROT_READ | PROT_WRITE, MAP_SHARED,
                      mystruct_fd, 0);

What I do now?我现在应该做什么? I simply write MyStruct fields one by one (and entries[] by chunks via buffer) using write() .我只是使用write()一个一个地写入MyStruct字段(并通过缓冲区按块写入entries[] )。 At the end CRC32 checksum is written.最后写入CRC32校验和。

Everything works just fine on all available to me 64-bit systems.在我可用的所有 64 位系统上一切正常。 It seems that first 4 chars + 32-bit int are aligned into the single 64-bit chunk and uint64 simply expands into uint64_t , so after write everything is mmap 'ed correctly.似乎前 4 个字符 + 32 位int对齐到单个 64 位块中,并且uint64简单地扩展为uint64_t ,所以在写入后一切都正确地被mmap了。

However, I am afraid that on 32-bit system or some specific OS/architecture, where different alignment rules are applied and there is no uint64_t and uint64 expands into something like:但是,恐怕在 32 位系统或某些特定的操作系统/体系结构上,应用了不同的 alignment 规则并且没有uint64_t并且uint64扩展为:

{
    int val1;
    unsigned long int val2;
}

I will get incorrect mmap 'ing after write.写后我会得到不正确的mmap

What is a portable way to write such a structure to file and use mmap after that?将这样的结构写入文件并在此之后使用mmap的可移植方式是什么?

PS Actually, this is all about PostgreSQL extension and uint64 here is pg_atomic_uint64 , but I think that question is more general. PS 实际上,这都是关于 PostgreSQL 扩展和uint64这里是pg_atomic_uint64 ,但我认为这个问题更笼统。

You shouldn't write the members one by one, because that won't account for padding between members.您不应该一个一个地写成员,因为这不会考虑成员之间的填充。 Write the whole thing all at once:一次性写下全部内容:

write(fd, MyStruct, sizeof(MyStructHdr) + entry_count * sizeof(uint64));

where entry_count is the number of elements in the flexible array member.其中entry_count是灵活数组成员中的元素数。

If you need to write each member separately for atomicity, you can use the offsetof macro to get the size including padding.如果您需要单独编写每个成员以实现原子性,您可以使用offsetof宏来获取包含填充在内的大小。

write(fd, &MyStruct->text, offsetof(MyStructHdr, version_num));
write(fd, &Mystruct->version_num, offsetof(MyStructHdr, init_value) - offsetof(MyStructHdr, version_num));
write(fd, &MyStruct->init_value, offsetof(MyStructHdr, entries) - offsetof(MyStructHdr, init_value));

then write the MyStruct->entries array in chunks.然后分块写入MyStruct->entries数组。 You don't need to worry about padding there, because sizeof on an array element includes the padding between elements (this ensures that sizeof array == element_count * sizeof array[0] );您无需担心那里的填充,因为数组元素上的sizeof包括元素之间的填充(这确保sizeof array == element_count * sizeof array[0] );

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM