这种计算数组长度的方法是如何工作的?

How does this way of computing array-length work?

我是 C++ 的新手,偶然发现了这种用指针计算数组长度的方法,我并不完全理解。我到处都看了,但似乎没有任何地方可以解释它是如何工作的,我只是听说它应该是计算数组长度的一种糟糕方法,但为什么会这样,它是如何工作的?

代码看起来像这样:

int array[4] = [0, 1, 2, 3]
//...
int length = *(&array + 1) - array

据我所试,它似乎确实有效,但我不完全明白为什么。我知道一点指针逻辑,但这个语句对我来说似乎很奇怪,因为你实际上是在获取数组的地址(我想是第一个元素)并向它添加一个(我可以想象这会给你地址在最后一个元素之后,但我不明白你为什么要取消引用它)。最让我困惑的是,这一切都被数组本身减去了?!没有索引或任何东西。

如果有人能够向我解释这一点,以及为什么它应该是坏的,那真的很有帮助。

谢谢。

&array

这是指向对象 array 的指针。是数组类型的单数对象

&array + 1

将一个数字添加到一个指针会生成一个指向对象数组中该对象的连续同级对象的指针。添加 1 产生下一个兄弟。出于此指针算法的目的,单个对象被视为单个对象的数组。因此,加 1 是允许的,它会产生一个指向比喻数组末尾的指针。

*(&array + 1)

严格来说,这通过一个指向末尾的指针进行了间接寻址,并且可以说程序的行为是未定义的。

但我们假设这不是问题。间接操作在数组后的地址处为 (non-existent) 对象生成一个左值。

*(&array + 1) - array

这里,减法的操作数是数组的左值。一个是实际数组,另一个是假设的数组数组中的假设兄弟元素。在这种情况下,这些数组隐式转换为指向相应数组第一个元素的指针。

从技术上讲,转换后的指针之间的减法是未定义的,因为它们是指向单独数组元素的指针,因此可以说程序的行为由于另一个原因是未定义的。

但我们假设这不是问题。减去指向同一数组的两个元素的指针的结果产生元素的距离。相邻数组第一个元素之间的距离恰好是第一个数组中元素的数量。

why it's supposed to be bad exactly.

请注意前面部分中的部分,这些部分表示程序的行为是未定义的。太糟糕了。

此外,您在理解它的作用时遇到了问题。太糟糕了。

获得数组大小的推荐方法是使用std::size(array)

代码的逻辑是首先假装在 [=12= 结束后立即在内存中找到第二个数组 int(为了便于讨论称为 array2) ].我说“假装”是因为 array2 实际上并不存在。

基于那个伪装,代码的逻辑就是;

  1. &array 是指向 array 的指针。它的类型为 int (*)[4](对于人类来说更详细地描述为“指向四个 int 的数组的指针”);
  2. &array + 1 是指向 array2 的指针;
  3. 取消引用该指针,即计算 *(&array + 1) 给出(对)array2;
  4. 在表达式 *(&array + 1) - array 中,项 *(&array + 1)array 均隐式转换为 int *。这些指针的值分别是&array2[0]&array[0]。所以表达式 *(&array + 1) - array 等价于 &array2[0] - &array[0];
  5. 由于 array2 在内存中紧跟在 array 的最后一个元素之后,&array2[0] 等于 &array[4] (即 non-existent array[4])。减去两个 int * 类型的指针得到它们之间 int 的数量,即 &array[4] - &array[0] 给出一个值 4std::size_t 类型);
  6. 由于 length 的类型为 int,因此具有值 4std::size_t 被转换为 int, i.e. to the value 4`。

这就是您正在测试的(大概)编译器(或多个编译器)正在使用的逻辑。

问题 - 即为什么人们认为它不好 - 是因为 array2array[4] 实际上并不存在。所以 - 根据标准 - 上面的第 3 步给出了未定义的行为。所有后续点(其中提到 non-existent array2 或 non-existent array[4])也涉及未定义的行为。未定义行为的意思是标准没有定义会发生什么——所以编译器不需要实现代码的逻辑。

一种在不给出未定义行为的情况下获取 array 大小的方法很简单 length = sizeof(array)/sizeof(array[0]) 因为 sizeof 运算符仅检查其参数的类型(并且不评估它们) 因此避免了未定义的行为。 sizeof(array) 给出了四个 int 数组的大小(以字节为单位),sizeof(array[0]) 给出了单个 int 的大小(以字节为单位),因此将它们相除得到 4.

高级说明: 使用 sizeof 的方法的局限性在于它在存在指针转换的情况下不起作用。例如,如果 array 实际上是一个指针(如果将原始数组作为参数传递给函数,就会发生这种情况)计算将不会(必然)给出 4.[=60= 的值]