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

C中的指针标记是否未根据标准定义?,c,language-lawyer,standards-compliance,C,Language Lawyer,Standards Compliance,一些动态类型的语言用作快速识别或缩小所表示值的运行时类型的方法。实现这一点的经典方法是将指针转换为适当大小的整数,并在最低有效位上添加一个标记值,对于对齐对象,该位假定为零。当需要访问对象时,标记位被屏蔽,整数被转换为指针,指针被正常解引用 这本身就是正确的,但它取决于一个巨大的假设:对齐指针将转换为一个保证在正确位置有零位的整数 是否可以根据标准的文字对此进行保证 尽管标准第6.3.2.3节(参考C11草案)指出从指针到整数的转换结果是实现定义的,我想知道的是,6.5.2.1和6.5.6中的

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

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

是否可以根据标准的文字对此进行保证


尽管标准第6.3.2.3节(参考C11草案)指出从指针到整数的转换结果是实现定义的,我想知道的是,6.5.2.1和6.5.6中的指针算术规则是否有效地约束指针->整数转换的结果,以遵循许多程序已经假设的相同的可预测算术规则。(6.3.2.3注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] ?
(如果我理解正确,如果实现提供了
uintpttr\t
,那么6.3.2.3第6段中暗示的未定义行为是不相关的,对吗?)

如果所有这些都成立,那么我将假设这意味着您实际上可以依赖于指向对齐的
单元格
数组的元素的任何转换指针的低位来自由地进行标记。他们做了吗


(据我所知,这个问题是假设性的,因为通常的假设适用于通用平台,如果你发现了一个不适用的平台,你可能不想参考C标准而不是平台文档;但这与问题无关。)

关于标准的相关部分,你是对的。供参考:

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

任何指针类型都可以转换为整数类型。除非前面指定,否则结果是实现定义的。如果结果不能用整数类型表示,则行为未定义。结果不必在任何整数类型的值范围内

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

我猜你明确问题的答案是:

是否可以根据标准的文字对此进行保证

是“是”,因为标准对这种行为下赌注,并说实现必须定义它。可以说,出于同样的原因,“不”也是一个很好的答案

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

有没有可能根据合同的约定来保证这一点 标准

实现可以保证这一点。将指针转换为整数的结果是实现定义的,实现可以以任何方式定义它,只要它满足标准的要求

该标准绝对不能保证这一点

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

所有指针到指针、指针到整数和整数到指针的转换都只是复制了表示形式

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

标准中没有禁止这一点

一句话:如果你对当前系统如何表示指针做了某些假设,那么像你描述的那样,一个用指针表示的游戏方案就可以工作——只要这些假设对当前系统有效

但是没有这样的假设是100%可靠的,因为标准没有说明指针是如何表示的(除了它们对于每种指针类型都有固定的大小,并且表示可以被看作是一个无符号字符的数组)


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

回头看。。。上面例子的第三部分(“所以…”)也不成立;只有通过循环推理,这种东西应该在x86上工作/工作,它看起来才成立。交换指针和int的顺序不会影响访问,但是交换whi