ram*_*ion 2 c arrays compiler-construction pointers pointer-arithmetic
因此,正如我从Michael Burr 对此答案的评论中所学到的,C标准不支持从数组中第一个元素之后的指针进行整数减法(我想这包括任何已分配的内存).
从C99 + TC1 + TC2组合的 6.5.6节(pdf):
如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,则评估不应产生溢出; 否则,行为未定.
我喜欢指针算法,但这从来都不是我以前所担心的.我一直认为给定:
int a[1];
int * b = a - 3;
int * c = b + 3;
Run Code Online (Sandbox Code Playgroud)
那个c == a.
因此,虽然我相信我以前做过那样的事情而且没有被咬过,但这一定是由于我曾经使用的各种编译器的善意 - 他们已经超出了标准要求的范围.使指针算术以我认为的方式工作.
所以我的问题是,这有多常见?是否有常用的编译器不能为我做那种善意?超出数组边界的正确指针算法是一个事实上的标准吗?
MSDOS FAR指针存在这样的问题,这些问题通常通过在实模式下"巧妙地"使用段寄存器与偏移寄存器的重叠来实现.其结果是16位段向左移4位,并加到16位偏移量,得到20位物理地址,可以解决1MB,这很多,因为每个人都知道没有人会像多达640KB的RAM.;-)
在保护模式下,段寄存器实际上是内存描述符表的索引.典型的DOS扩展运行时通常会安排事情,以便可以像处理实模式一样处理许多段,这使得从实模式移植代码变得容易.但它有一些缺陷.主要是,分配之前的段不是分配的一部分,因此其描述符可能甚至不是有效的.
在受保护模式的80286上,只是加载一个段寄存器,其值会导致无效的描述符加载,这将导致异常,无论该描述符是否实际用于引用内存.
在分配之后的一个字节处可能发生类似的问题.指针上的最后一个++可能已经转移到段寄存器,导致它加载一个新的描述符.在这种情况下,可以合理地预期内存分配器可以在分配范围的末尾之外安排一个安全描述符,但是期望它安排更多的安全描述符是不合理的.