根据标准,C中的指针标记是否未定义?

一些动态类型语言使用指针标记作为识别或缩小所表示值的运行时类型的快速方法。 执行此操作的经典方法是将指针转换为适当大小的整数,并在最低有效位上添加标记值,对于对齐对象,这些位被假定为零。 当需要访问对象时,标记位被屏蔽掉,整数转换为指针,指针被正常解除引用。

这本身就是有序的,除了它都取决于一个巨大的假设:对齐的指针将转换为保证在正确位置具有零位的整数。

是否可以根据标准的字母来保证这一点?


虽然标准的6.3.2.3节(参考C11草案)说从指针到整数的转换结果是实现定义的,但我想知道的是6.5.2.1和6.5.6中的指针算术规则是否有效约束指针 – >整数转换的结果遵循许多程序已经假设的相同的可预测算术规则。 (6.3.2.3注释67似乎表明这是标准的预期精神 ,而不是那意味着很多。)

我特别想到的情况是,人们可能会分配一个大型数组作为动态语言的堆,因此我们所讨论的指针就是这个数组的元素。 我假设C分配数组本身的开始可以通过某些辅助手段放置在对齐位置(尽管如此也是这样讨论)。 假设我们有一个八字节“cons cell”数组; 我们可以保证指向任何给定单元格的指针将转换为标记最低三位的整数吗?

例如:

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标准而不是平台文档;但这不是重点。)

这本身就是有序的,除了它都取决于一个巨大的假设:对齐的指针将转换为保证在正确位置具有零位的整数。

是否可以根据标准的字母来保证这一点?

实现可以保证这一点。 将指针转换为整数的结果是实现定义的,并且实现可以按照自己喜欢的方式定义它,只要它符合标准的要求即可。

标准绝对不能保证这一般。

一个具体的例子:我曾经使用过Cray T90系统,它有一个在类UNIX操作系统下运行的C编译器。 在硬件中,地址是包含64位字地址的64位字; 没有硬件字节地址。 字节指针( void*char* )是通过在64位字指针的其他未使用的高阶3位中存储3位偏移而在软件中实现的。

所有指向指针的指针,指向整数的指针和整数到指针的转换只是复制了表示。

这意味着指向8字节对齐对象的指针在转换为整数时,可以在其低位3位中具有任何位模式。

标准中没有任何内容禁止此操作。

底线: 如果您对当前系统如何表示指针做出某些假设 – 只要这些假设恰好对当前系统有效,那么像您描述的那种使用指针表示来玩游戏的方案就可以工作。

但是没有这样的假设可以100%可靠,因为标准没有说明如何表示指针(除了它们是每个指针类型的固定大小,并且表示可以被视为unsigned char的数组) 。

(该标准甚至不保证所有指针的大小都相同。)

你对标准的相关部分是正确的。 以供参考:

整数可以转换为任何指针类型。 除非先前指定,否则结果是实现定义的,可能未正确对齐,可能不指向引用类型的实体,并且可能是陷阱表示。

任何指针类型都可以转换为整数类型。 除了之前指定的以外,结果是实现定义的。 如果结果无法以整数类型表示,则行为未定义。 结果不必在任何整数类型的值范围内。

由于转换是实现定义的(除非整数类型太小,在这种情况下它是未定义的),标准不会告诉您有关此行为的任何信息。 如果您的实现提供了您想要的保证,那么您已经设置好了。 否则,太糟糕了。

我猜你明确问题的答案:

是否可以根据标准的字母来保证这一点?

是“是”,因为标准对此行为表示支持,并表示实施必须对其进行定义。 可以说,“不”也是出于同样原因的答案。