我的项目中有两个进程P1和P2。它们使用boost::interprocess::shared_memory
创建一个正常工作的共享内存段(同步没有问题)。我的用例包括从P1向P2发送一个POD类型(a trivially copyable type)。假设POD类型如下所示:
struct Widget
{
char val;
int length;
}
我认为这很容易,并提出了一种似乎通用于所有POD类型的方法:
在共享内存中创建一个char buff[MAX_SIZE]
。随后执行以下操作:
// P1
Rectangle R = {'a', 4};
memcpy(pointer_to_shared_memory, &R, sizeof(R));
// P2
Rectangle R;
memcpy(&R, pointer_to_shared_memory, sizeof(R));
// use R
让我困惑的是,即使对象的模式没有改变,编译器在分别编译P1和P2时引入的默认填充会发生什么?尽管P1和P2会在类似的条件下编译(构建标志等),以及在相同的系统上,相同的gcc版本上,我仍然不能把填充需求留给gcc,它会在两个不同的场景中随意执行。
例如,在这里,我期望P1和P2都具有Widget的表示:
v---
llll
其中v是char瓦尔,l是length(总共8个字节)。我的pod可能包含uint 8,unint 16等,并且随着时间的推移会变得复杂。我有一种感觉,我不能依赖编译器来为两个不同的进程修复相同的内存填充,即使它们的模式在源代码中是固定的。
如果P1和P2中的模式相同,是否有办法保证填充也是一致的,并且编译器会以一致的方式处理填充?我不想使用pragma
或pack
预处理器,因为它们会限制我可以发送的POD类型。
像flatbuffers
这样的序列化库能处理所有这些吗?我必须为此使用一个序列化库吗?(我希望不是!我不想引入对POD类型的对象进行序列化/反序列化的额外开销)
1条答案
按热度按时间rwqw0loc1#
我仍然不能把填充要求留给gcc,它会在两个不同的场景中随意执行。
结构布局/填充量不是任意的,不会因编译器的运行而不同。如果不同,则无法进行单独编译。不要管IPC。想象一下如果Widget是在两个独立文件的头文件中定义的。编译器在编译两个不同的文件时改变填充是不行的。libc中的任何函数都接受一个结构体如果填充/布局不一致,(例如lstat)将毫无用处。