这种指针标记方法是否符合C标准?

(回顾指针标记:对象的大小意味着其指针中的有限位数将始终未使用,并且可以重新用于其他用途,例如标记对象的类型。)

对我之前关于这个主题的问题的一个很好的答案证实,将指针转换为整数并将事情转换为整数的天真方法在技术上无法依赖于工作(无视其在实践中的受欢迎程度)。

再考虑一下,我想我有一个适用于原始问题中描述的特定情况的解决方案(所有对象都是相同的大小,所有对象都是从单个“堆”数组中分配的)。 有人可以证实我的推理吗?

// 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)吗?

(不,我不知道为什么这种技术性会如此强烈地影响我的想法;是的,可移植性很容易通过其他方式实现。)

在这里,我认为你唯一需要更加小心的是你的整数类型。 不要使用int

  • 指针差异的正确类型是ptrdiff_t
  • sizeof的结果是size_t是无符号类型
  • 你在size_t类型和ptrdiff_t之间做% ,所以结果很可能是size_t ,所以无符号值
  • size_t转换为int是实现定义的(因此不可移植),通常它只会丢弃高位

int会工作很长一段时间,但是当你在64位处理器上使用非常大的数组时,你会后悔的(经过几天的调试)