c - 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;
我不明白他们为什么要减去两个指针。它不会返回相同的值(零)吗?它与Linux IPC有关吗?这真的很令人困惑。请帮忙
解决方案
我不明白他们为什么要减去两个指针。它不会返回相同的值(零)吗?
是的,但前提是该base
成员是结构中的第一个成员。l_base
是结构的地址,而s_base
是该结构中base
成员的地址,两者都转换为指向unsigned8
.
C99 及更高版本确实明确表示如果base
是结构中的第一个成员,则它与结构具有相同的地址。
它与Linux IPC有关吗?
不,不是我能看到的。
然而,有一个与共享内存进程间通信相关的模糊相似的模式。
假设您有一个struct shared_data *shared
, 指向共享内存。
因为每个进程都有自己的虚拟地址空间,虽然 的内容是shared
共享的,但每个进程可以拥有不同的地址,即shared
自身的值可以变化。
这意味着在共享内存中使用指针基本上是没有用的。仅仅因为一个进程中的特定指针值指向共享内存的特定部分,并不意味着它在所有进程中都这样做。
您需要存储相对于 的偏移量shared
,而不是指针,以便0
引用共享内存区域中的第一个地址,依此类推。(或与共享内存的开头相关的其他类似方案。)
为此,您可能会看到类似于
intptr_t shared_offset = (intptr_t)shared;
该类型intptr_t
是可移植的 POSIX 兼容类型。在 Linux 中,您可以使用long
. 问题是,存在使用 的旧代码,int
甚至int
在其示例中使用的旧书籍,但它无法在 64 位架构上正常工作,例如较新的 Intel 和 AMD 计算机。
无论如何,要将 say 处的字节偏移量转换为指向 say的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;
这种方法很脆弱,因为它需要非常小心地正确编写所有这些表达式,同时确保底层逻辑也是正确的。(我认为这类似于尝试用一只手敲击,同时用另一只手画一个圆圈。大多数人需要大量练习才能正确完成。)
如果可能的话,最好使用数组和数组索引,而不是共享内存开头的偏移量。
我只看到当每个元素的大小变化时才合理使用这种偏移方法。即使这样,通常也有更好的算法方法。
推荐阅读
- python - 来自 CMD 或 .bat 文件执行但不是来自 IDE 的 Google_api 凭据错误
- python - 在 docker 容器中运行时 Python 中的 SFTP 密钥错误
- python-3.x - 如何添加两个具有不同货币符号的浮点字段?
- regex - 使用排序规则和正则表达式比较 mongodb 中的全角和半角日文字符
- oracle - 用 PL/SQL 读取 XML 文档,XML 标签不固定
- android - 从 Google Play 外部安装的 APK 是否可以在没有任何弹出窗口的情况下更新?
- matlab - MATLAB 到 Scilab 的转换:mfile2sci 错误“文件不包含指令”
- c++ - 将 1 居中放在顶部
- angular - 如何在 Angular 7 中使用 iframe
- python - Python 列表约定列表