C负数组索引

这是我的结构:

struct Node { struct Node* data; struct Node* links[4]; } 

假设没有填充, Node->links[-1]保证指向Node::data

不保证; 这是未定义的行为:

  • 编译器相关的结构填充
  • Standard仅定义0和长度(包括)之间的数组索引
  • 可能的严格别名违规

在实践中,您很可能最终指向data ,但任何访问它的尝试都将导致UB。

数组下标是根据指针算法定义的,C99标准对指针算法有这样的说法:

如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,则评估不应产生溢出; 否则,行为未定义。

因此,严格来说,访问Node->links[-1] (即使只是获取Node->links[-1]的地址)也是未定义的行为。 所以你不能保证Node->links[-1]会得到Node::data

但正如许多评论家所提到的那样,它几乎总能奏效。 我仍然认为应该避免的编程习惯很差。 如果不是技术性,那么因为它要求对struct Node修改很容易导致编译器无法帮助你的错误。 当有人在datalinks之间添加内容时,事情会神秘地破坏。

union可能会帮助你。 像这样的东西:

 struct Node { union { Node *data; struct { Node *lnk[5]; } links; } } 

我会说是,但为什么不宣布它为

 struct Node { struct Node* links[5]; } 

几乎是的

是的,它几乎肯定指向data ,但它可能不是一个保证。

你确实得到了一个保证, x[-1]*(x - 1) ,所以,根据你在x - 1的地址放置的东西,那么你确实有一种保证。 (并且不要忘记,当从指针中减去时,减量是项目的大小。)

虽然其他人在严格别名的基础上提出异议,但在这种情况下类型是相同的,因此精心优化不应该删除您预期的行为。

我觉得是这样的。 但是标准没有保证没有填充。

编辑:但是标准还说如果“数组下标超出范围,行为是未定义的,即使某个对象显然可以使用给定的下标访问”。

这是实现定义,取决于实现焊盘结构和数组的方式。 但是,只要它以相同的方式填充结构和数组,它应该工作。