在联合中组合指针和整数

时间:2011-12-12 11:23:49

标签: c pointers integer unions

我已按如下方式定义了一个联盟:

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产生真的时?

5 个答案:

答案 0 :(得分: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),但指针上不存在这样的约束。
  4. 因此,我得出结论,最好的方法是有一个共同的初始元素告诉国家。

答案 1 :(得分:1)

我将回答一个不同的问题 - “这是一个好主意吗?”我从代码中看到的更重要的担心是别名问题。如果有可能编写一段具有

效果的代码,我会毫不惊讶(事实上,我会温和地期待它)
  • 将内容写入u.refcount
  • 将内容写入u.page
  • 阅读u.refcount
  • 发现您阅读的价值与您最初写的内容相同

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

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

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

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

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

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

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

如果您发现这种变化会使时间密集型例程的性能翻倍,那么可能值得处理这个问题。但是,如果你只是因为这是一个节省8个字节的聪明技巧来调查这个问题,那么你应该把它视为一个智力练习。

答案 2 :(得分:0)

我认为<stdint.h>和C99标准保证uintptr_tvoid*具有相同的尺寸,并且可以毫无损失地投放。

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

答案 3 :(得分:0)

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

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

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

答案 4 :(得分:0)

  

这总能保证有效吗?

没有。你不能读一个不同于最后写的联盟的成员。优化者确实考虑到了这一点,因此这不是一个理论问题。

  

uintptr_t和struct slab_header *是否有可能具有不同的表示形式,   因此,例如,当u.page == 8192时,u.refcount&lt; 4096收益是真的吗?

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