使用数组的地址获取过去的指针

时间:2013-12-14 01:07:25

标签: c++ c c++11 undefined-behavior c11

在C和C ++中,使用past-the-end指针来编写可以在任意大型数组上运行的函数通常很有用。 C ++提供std::end重载使这更容易。另一方面,在C中,我发现看到定义和使用宏的情况并不罕见:

#define ARRAYLEN(array) (sizeof(array)/sizeof(array[0]))

// ...

int a [42];
do_something (a, a + ARRAYLEN (a));

我还看过一个指针算术技巧,用于让这些函数对单个对象进行操作:

int b;
do_something (&b, &b + 1);

我发现类似的事情可以用数组来完成,因为它们被C(并且我相信,C ++)认为是完整的对象。"给定一个数组,我们可以在它之后立即派生一个指向数组的指针,取消引用该指针,并对结果对数组的引用使用数组到指针的转换,以获得原始数组的过去指针: / p>

#define END(array) (*(&array + 1))

// ...

int a [42];
do_something (a, END (a));

我的问题是:在取消引用指向不存在的数组对象的指针时,此代码是否显示未定义的行为?我对C和C的最新版本感兴趣C ++不得不说这个代码(不是因为我打算使用它,因为有更好的方法来实现相同的结果,但因为它是一个有趣的问题)。

3 个答案:

答案 0 :(得分:1)

我在我自己的代码中使用了它,(&arr)[1]

我很确定这是安全的。指向衰减的数组不是“左值到右值转换”,尽管它以左值开始并以右值结束。

答案 1 :(得分:1)

这是未定义的行为。

a的类型为array of 42 int

&a的类型为pointer to array of 42 int。 (注意这不是数组到指针的转换)

&a + 1也属于pointer to array of 42 int

类型

5.7p5州:

  

当向指针添加或从指针中减去具有整数类型的表达式时,结果具有指针操作数的类型。如果指针操作数指向数组对象的元素,则[...]否则,行为未定义

指针不指向数组对象的元素。它指向一个数组对象。所以“否则,行为未定义”是真的。行为未定义。

答案 2 :(得分:0)

它是C中的未定义行为,取消引用指向现有对象之外的指针,除非它本身是包含更多元素的更大对象的一部分。

但是,只要&array + 1是左值,使用array的基本思路就是正确的。 (有些情况下数组不是左值。)在这种情况下,这是一个有效的指针操作。现在要获取指向第一个元素的指针,您只需将其转换回基类型。在您的情况下将是

(int*)(&array + 1)

指向数组的指针的值保证与指向其第一个元素的指针的值相同,只有类型不同。

不幸的是,我没有看到一种方法来使这种表达式类型不可知,这样你就可以把它放在一个通用宏中,除非你转换为void*。 (使用gcc typeof扩展程序,例如) 所以你最好坚持使用便携式(array)+ARRAYLEN(array),那个应该适用于所有情况。

在一个奇怪的角落案例中,作为struct一部分并且从函数返回为rvalue的数组不是左值。我认为这个标准也允许在这里使用指针算法,但是我从来没有完全理解这个结构,所以我不确定它是否适用于那种情况。