一些动态类型语言使用指针标记作为一种快速方法来识别或缩小所表示值的运行时类型。执行此操作的经典方法是将指针转换为适当大小的整数,并在最低有效位上添加标记值,对于对齐的对象,最低有效位假定为零。当需要访问对象时,标记位被屏蔽掉,整数被转换为指针,指针被正常解除引用。
这本身就是有序的,除了它都取决于一个巨大的假设:对齐的指针将转换为保证在正确位置具有零位的整数。
是否可以根据标准的字母来保证这一点?
尽管标准第 6.3.2.3 节(参考 C11 草案)说从指针到整数的转换结果是实现定义的,但我想知道的是 6.5.2.1 和 6.5.6 中的指针算术规则是否有效约束指针->整数转换的结果遵循许多程序已经假定的相同的可预测算术规则。(6.3.2.3 note 67 似乎暗示这是该标准的预期精神,但这并不意味着什么。)
我特别考虑了一个可能分配一个大数组作为动态语言的堆的情况,因此我们正在谈论的指针指向这个数组的元素。我假设 C 分配的数组本身的开头可以通过某种辅助方式放置在对齐的位置(尽管也可以讨论这个)。假设我们有一个 8 字节的“cons 单元”数组;我们能否保证指向任何给定单元格的指针将转换为一个整数,其中最低三位可用于标记?
例如:
typedef Cell ...; // such that sizeof(Cell) == 8
Cell heap[1024]; // such that ((uintptr_t)&heap[0]) & 7 == 0
((char *)&heap[11]) - ((char *)&heap[10]); // == 8
(Cell *)(((char *)&heap[10]) + 8); // == &heap[11]
&(&heap[10])[0]; // == &heap[10]
0[heap]; // == heap[0]
// So...
&((char *)0)[(uintptr_t)&heap[10]]; // == &heap[10] ?
&((char *)0)[(uintptr_t)&heap[10] + 8]; // == &heap[11] ?
// ...implies?
(Cell *)((uintptr_t)&heap[10] + 8); // == &heap[11] ?
(如果我理解正确,如果实现提供,uintptr_t
那么 6.3.2.3 第 6 段中暗示的未定义行为是无关紧要的,对吧?)
如果所有这些都成立,那么我认为这意味着您实际上可以依赖任何转换后的指向对齐数组元素的指针的低位Cell
来自由进行标记。他们 && 会吗?
(据我所知,这个问题是假设性的,因为正常的假设无论如何都适用于通用平台,如果你找到了一个没有的地方,你可能不想参考 C 标准而不是平台文档;但这不是重点。)