我已经定义了一个union,如下所示:

union {
  uintptr_t refcount;
  struct slab_header *page;
} u;

保证page指针在页面边界上对齐(最可能是4096),并且永远不会为NULL 这意味着最低可能的地址将是4096

refcount将在0 .. 4095

在创建封闭结构时,我可以使用u.refcount = 0u.page = mmap(...)

这个联盟的代码将是这样的:

if (u.refcount < 4096) {
  /* work with refcount, possibly increment it */
} else {
  /* work with page, possibly dereference it */
}

这总是保证在完全符合POSIX的实现上工作吗? 是否有可能uintptr_tstruct slab_header *具有不同的表示形式,例如,当u.page == 8192u.refcount < 4096产生真?

===============>>#1 票数:3 已采纳

我不认为它“始终保证工作”,因为:

  1. uintptr_t是可选的(7.18.1.4)。
  2. void *可以转换为uintptr_t并返回(7.18.1.4)。 并不保证struct slab_header*就是这种情况。 void *具有与指向字符类型的指针相同的表示和对齐要求。 指向结构的指针不需要具有相同的表示或对齐(6.2.5 27)。 即使不是这种情况,也没有什么能保证sizeof(uintptr_t) == sizeof(void *) ,它显然可以更大并且仍然满足在均匀指针的典型情况下可转换为void *的要求。
  3. 最后,即使它们具有相同的大小并且是可转换的,指针值的表示也可能以与无符号整数的奇怪方式不同。 无符号整数的表示相对受限(6.2.6.2 1),但指针上不存在这样的约束。

因此,我总结出最好的方法是拥有一个告诉国家的共同初始元素。

===============>>#2 票数:1

我要回答一个不同的问题 - “这是个好主意吗?” 我从代码中看到的更重要的担心是别名问题。 我不会感到惊讶(事实上,我会温和地期待它),如果有可能写一段具有影响的代码

  • 写一些东西到u.refcount
  • u.page
  • 阅读u.refcount
  • 发现您阅读的价值与您最初写的相同

你可能会嗤之以鼻,但我已经看到了这种情况 - 如果你不了解危险,那么调试需要长时间。

你可能对这个特殊的联盟很安全; 我将把它留给那些对此类事物有更多经验的人(和/或C标准的副本)以做出判断。 但我想强调一下,这是值得担心的重要事项

还有另一项费用。 将union与“魔术”测试结合使用以发现存储在其中的内容 - 尤其是使用系统特定事实的内容 - 将使您的代码更难以阅读,调试和维护。 您可以采取措施来缓解这一事实,但这始终是一个问题。

当然,当有人试图在奇怪的机器上使用它时,代码的成本根本不起作用。

正确的解决方案可能是以某种方式构建代码,以便关注数据布局的唯一代码是几个小的inline访问例程,以便您可以轻松地交换如何存储内容。 组织您的代码以使用编译时标志来选择哪一个!

现在我已经说了所有这些,我真的想问的问题(并希望让你养成考虑的习惯):“它值得吗?” 您正在牺牲自己的时间,代码可读性,编程的简易性和可移植性。 你有什么收获?

很多人忘记提出这个问题了,他们编写复杂的错误代码时,简单易用,易于编写和读取代码同样出色。

如果你发现这个改变会使时间密集型例程的性能翻倍,那么它可能值得处理这个hack。 但是如果你正在研究这个只是因为它是一个节省8个字节的聪明技巧,那么你应该把它视为一个智力练习。

===============>>#3 票数:0

我认为<stdint.h>和C99标准保证uintptr_tvoid*具有相同的大小并且可以不丢失地进行转换。

针对指针进行页面对齐是一个实现细节。

===============>>#4 票数:0

该代码应该有任何问题。 但是对于任何情况,您都可以在程序的init中进行检查:

if (sizeof(uintptr_t) != sizeof (struct slab_header*)
{
    print error
}

但似乎有些东西(或不清楚)。 当你有一个页面时,你希望“refcount”为0。 页面为NULL时不为零?

===============>>#5 票数:0

这总能保证有效吗?

不可以。你不能读到与最后一个不同的工会成员。 优化器确实考虑到了这一点,因此这不是一个理论问题。

是否有可能uintptr_t和struct slab_header *具有不同的表示形式,例如,当u.page == 8192时,u.refcount <4096会产生真?

这在理论上也是可能的。 我想不出它出现的当前实现。

  ask by Blagovest Buyukliev translate from so

未解决问题?本站智能推荐:

1回复

访问指向联合的指针中的指针

所以我有一个包含联合的结构,如下所示: 我不明白如何访问结构中的工会成员。 我一直在尝试这样做,如下所示: 但是,当我尝试这样做时,我会遇到段错误。 我访问这些错误吗? 否则我应该怎么做? 编辑:对不起,我专注于格式设置,我搞砸了TEST声明。 它是固定的。
1回复

C编程:访问联合中的指针

有人可以帮我用联合访问指针吗,我不断收到[错误]无效类型参数'->'(具有'struct node')。 这是其中包含我的数据结构的代码段: 如果有人能指出我如何在联合体内访问指针,那将很棒。 多谢你们。
3回复

如何在C中的联合中使用指针?

我想初始化这个结构: 如果在声明变量时尝试初始化此结构,则会出现错误: 变量gpStr不能用于初始化结构 但是它可以在函数内部初始化而没有问题: 为什么在声明结构时无法对其进行初始化? 我认为工会有一种特殊的行为,因为如果我不使用工会,这个问题就不存在。 例
1回复

为联合分配内存以及联合指针和指针联合之间的区别

由于我的问题在这里不能自信地回答说,我再问一次在这里希望有人知道确切原因: 指向union的指针和包含指向其元素的指针的union之间是否有任何区别(除了语法之外)? 此示例中生成的程序集是相同的。 只要我永远不会访问其他成员,是否允许仅为其中一个成员(不是最大的成员)分配内
4回复

帮助将指针投射到联合

我正在从事C固件项目。 我有一个定义为的工会, 我还有一个具有此原型的函数, 以及类型为LONGVALUE的变量定义为, 问题:我用数组​​(tempBuff1)中的值填充union变量的各个字节,然后我希望将union中第一个元素的地址传递给一个函数,该函数会将其打印
1回复

C:指针,联合和地址

我想在值上打印出一些地址。 以下是我所得到的,并且必须打印出我想要的内容。 输出结果如下: 但这看起来很丑,我需要使用工会来做到这一点。 而且我遇到了以下困难。 我得到的错误 在行printf("%p %.08x %.08x\\n" 的线程1: EXC_B
2回复

将联合指针声明为函数

我有一些我不太明白的代码。 因此,在创建此联合后,将以一种奇怪的方式使用它。 然后称为正常函数 这是如何工作的? 在任何地方都没有代码说明此“功能”的工作原理。
2回复

C联合指向数组的指针

我有一个无符号的16位整数数组: 数组的第7个元素的位表示某种状态。 我想以一种简单的方式获取并设置此状态的值,而不必进行移位,也不必每次状态更改时都将新值复制到数组中。 所以我创建了一个带有结构和指针的联合: 我的初始化例程希望状态指针指向数组的第7个元素,因此我尝试:
2回复

C结构,指向结构的联合指针

我有一个typedeffed结构和一个联合。 联合包含struct和单个uint32_t 。 目标是为foo分配一个与结构中的“位”相对应的值。 foo变成: 谁能确切解释这里发生了什么(指向结构指针的工会指针,而推迟给工会成员的工会指针?)? 其次:为什么除了1,3和
2回复

为什么取消对外部联合的指针的取消定义?

我有以下代码。 为什么以以下方式取消定义联合指针的undefined?