我目前正在研究用C完全开发的遗留代码中的一个问题 . 它使用共享内存概念 . 我想了解其中使用的一些表达式 . 假设一个结构
> typedef struct
> {
> void* base;
> ....
> }shm_test_t;
表达式是这样的,
> shm_test_t test;
> test.base = (void*)(unsigned8*)&test;
> unsigned8* l_base = (unsigned8*)test.base;
> unsigned8* s_base = (unsigned8*)&(test.base);
然后,他们这样做了
unsigned8 l_diff = l_base - s_base;
unsigend8 s_diff = s_base - l_base;
我无法理解他们为什么减去两个指针 . 它不会返回相同的值(零)吗?它与Linux IPC有关吗?这真令人困惑 . 请帮忙
1 回答
是的,但仅当
base
成员是结构中的第一个成员时 .l_base
是结构的地址,而s_base
是该结构中base
成员的地址,两者都转换为指向unsigned8
的指针 .C99和更高版本确实明确说明如果
base
是结构中的第一个成员,它具有与结构相同的地址 .不,不是我能看到的 .
但是,存在与共享内存进程间通信相关的模糊类似模式 .
假设你有
struct shared_data *shared
,指向共享内存 .因为每个进程都有自己的虚拟地址空间,虽然
shared
的内容是共享的,但每个进程可以将它放在不同的地址,即shared
本身的值可以变化 .这意味着在共享内存中使用指针基本上是无用的 . 仅仅因为一个进程中的特定指针值指向共享内存的特定部分,并不意味着它在所有进程中都这样做 .
您需要存储相对于
shared
的偏移量而不是指针,以便0
指向共享内存区域中的第一个地址,依此类推 . (或者相对于共享内存开头的其他类似方案 . )为此,您可能会看到类似的代码
intptr_t
类型是便携式POSIX兼容类型 . 在Linux中,您可以使用long
. 问题是,存在使用int
的旧代码,甚至在他们的示例中使用int
的旧书,但它不能在64位架构上正常工作,例如较新的Intel和AMD计算机 .无论如何,要将
shared[5].next
处的字节偏移转换为指向footype
的指针,比如footype *foo
,您需要使用要么
两者都是等价的;前者直接使用
shared
指针,后者使用shared_offset
变量 .从
foo
到偏移的逆转换例如是要么
这种方法很脆弱,因为正确地编写所有这些表达式需要花费很多精力,同时确保底层逻辑也是正确的 . (我认为它类似于试图用一只手敲击,同时用另一只手画一个圆圈 . 大多数人需要做很多练习才能做到 . )
如果可能的话,最好使用数组和数组索引,而不是从开头到共享内存的偏移量 .
我只看到这种偏移方法在每个元素的大小变化时合理使用 . 即便如此,通常还有更好的算法方法 .