C中两个表达式之间的区别

Difference between two expressions in C

我目前正在处理完全用 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;

我不明白他们为什么要减去两个指针。它不会 return 相同的值(零)吗?与Linux IPC有关吗?这真是令人困惑。请帮忙

I can't understand why they are subtracting two pointers. Won't it return the same value(zero)?

是,但前提是 base 成员是结构中的第一个成员。 l_base 是结构的地址,而 s_base 是该结构中 base 成员的地址,两者都转换为指向 unsigned8.

的指针

C99 及更高版本确实明确指出,如果 base 是结构中的第一个成员,则它与结构具有相同的地址。

Is it related to Linux IPC?

不,我看不到。


然而,有一个与共享内存进程间通信相关的模糊相似模式。

假设您有一个 struct shared_data *shared,它指向共享内存。

因为每个进程都有自己的虚拟地址space,虽然shared内容是共享的,但是每个进程可以在不同的地址拥有它,即 shared 本身的值可以变化。

这意味着在共享内存中使用指针基本上是没有用的。仅仅因为一个进程中的特定指针值指向共享内存的特定部分,并不意味着它在所有进程中都如此。

需要相对于shared存储offsets而不是指针,这样0就指向了共享内存区域的第一个地址,等等。 (或其他一些与共享内存开头相关的类似方案。)

为此,您可能会看到类似于

的代码
intptr_t  shared_offset = (intptr_t)shared;

类型 intptr_t 是可移植的 POSIX 兼容类型。在Linux中,可以使用long。问题是,存在使用 int 的旧代码,甚至在他们的示例中使用 int 的旧书,但它在 64 位架构(如较新的 Intel 和 AMD 计算机)上无法正常工作,例如。

无论如何,要将 shared[5].next 处的字节偏移量转换为指向 footype 的指针,例如 footype *foo,您需要使用

foo = (footype *)((char *)shared + shared[5].next);

foo = (footype *)(shared_offset + shared[5].next);

两者是等价的;前者直接使用shared指针,后者使用shared_offset变量

foo到偏移量的逆向转换,例如

offset =  (ptrdiff_t)((char *)foo - (char *)shared);

offset = (intptr_t)foo - shared_offset;

这种方法很脆弱,因为它需要非常小心地正确编写所有这些表达式,同时确保底层逻辑也是正确的。 (我认为这类似于尝试用一只手敲击,同时用另一只手画一个圆圈。大多数人需要大量练习才能正确完成。)

如果可能的话,最好使用数组和数组索引,而不是共享内存开头的偏移量。

我只见过这种偏移方法在每个元素的大小不同时使用得当。即使那样,通常也有更好的算法方法。