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

标签 c language-lawyer standards-compliance

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

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

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


虽然标准部分 6.3.2.3(引用 C11 草案)说从指针到整数的转换结果是实现定义的,但我想知道的是指针算法是否符合 6.5.2.1 和 6.5 中的规则.6 有效地限制指针-> 整数转换的结果遵循许多程序已经假定的相同的可预测算术规则。 (6.3.2.3 注释 67 似乎表明这是标准的预期精神,但这并不意味着什么。)

我特别考虑的是可能分配一个大数组作为动态语言的堆的情况,因此我们讨论的指针是指向该数组元素的。我假设 C 分配的数组本身的开始可以通过一些辅助方法放置在对齐的位置(不过也一定要讨论这个)。假设我们有一个八字节的“cons cells”数组;我们能否保证指向任何给定单元格的指针将转换为一个整数,最低三位可用于标记?

例如:

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

最佳答案

This by itself is all in order, except it all hinges on one colossal assumption: that the aligned pointer will convert to an integer guaranteed to have zero bits in the right places.

Is it possible to guarantee this according to the letter of the standard?

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

标准绝对一般保证这一点。

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

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

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

标准中没有任何内容禁止这样做。

底线:一个像你描述的那样的方案,玩指针表示的游戏,可以工作如果你对当前系统如何表示指针做出某些假设-- 只要这些假设恰好对当前系统有效。

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

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

关于c - 根据标准,C 中的指针标记是否未定义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18578258/

相关文章:

c - 在分配的内存之外使用数组索引看起来很好,怎么样?

c++ - 无法从多维数组的初始值设定项推断边界

c++ - 如果初始化或销毁被未处理的异常终止,那么完全构造的子对象是否一定要销毁?

html - 如何在 Firefox 的标题样式工具提示中添加换行符?

c - C 中的逻辑运算符导致我的循环出现问题?

c++ - 游戏循环不工作 ncurses

c++ - main() 真的是 C++ 程序的开始吗?

javascript - XHTML/HTML/JS 语法 : When do I use &?

c - free 会导致内存损坏

c++ - 使用 gcc 的别名模板替换和推断失败