(回顾指针标记:对象的大小意味着其指针中的有限位数将始终未使用,并且可以重新用于其他用途,例如标记对象的类型。)
关于这个主题的excellent answer到我的previous question证实了将指针转换为整数并对这些整数做事的天真方法在技术上无法依赖于工作(无视其在实践中的受欢迎程度)。
在考虑更多内容之后,我认为我有一个适用于原始问题中描述的特定情况的解决方案(所有对象都是相同的大小,所有对象都是从单个“堆”数组中分配的)。有人可以证实我的推理吗?
// given:
typedef Cell ...; // such that sizeof(Cell) == 8
Cell heap[1024]; // or dynamic, w/e
// then:
void * tagged = ((char *)&heap[42]) + 3; // pointer with tag 3 (w/e that means)
int tag = ((char *)tagged - (char *)heap) % sizeof(Cell); // 3
Cell * ptr = (Cell *)((char *)tagged - tag); // &heap[42]
用文字表示:没有关于指针的整数表示的假设。通过索引指向对象内的字节来应用标记。 (这当然是允许的。)
指针减法返回同一数组中两个对象的索引差异。对象中的字节地址应该是连续的,因此通过获取所寻址字节的索引并从该索引中删除所有前面单元格的大小,将标记值转换为标记;通过删除现在已知的索引偏移量,可以将标记指针恢复为Cell指针。
这是否符合标准,因此是一种便携式指针标记方法?如果将数组的类型转换为其他内容,仍然允许指针减法工作,在这种情况下是char吗?我可以这样使用sizeof(Cell)
吗?
(不,我不知道为什么这种技术性在我脑海中如此吸引;是的,通过其他方式很容易实现可移植性。)
答案 0 :(得分:5)
在这里,我认为你必须更加小心的是你的整数类型。不要使用int
:
ptrdiff_t
。sizeof
的结果是size_t
无符号类型%
类型和size_t
之间进行了ptrdiff_t
,因此结果很可能是size_t
,因此无符号值size_t
转换为int
是实现定义的(因此不可移植),通常只会丢弃高阶位 int
将会工作很长时间,但是当你在64位处理器上使用非常大的数组时,你会后悔(经过几天的调试)