将2D数组视为1D数组 [英] Treating 2D array as 1D array

查看:108
本文介绍了将2D数组视为1D数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我们有一个二维int数组:

Let's say we have a 2D int array:

int a[3][4] = { { 1,3,2,4 }, { 2,1,5,3 }, { 0,8,2,3 } };

获取其地址并将其重新解释为指向int s的一维数组的指针是否合法有效?基本上:

Is it legal and valid to take its address and reinterpret it as a pointer to 1D array of ints? Basically:

int *p = reinterpret_cast<int *>(&a);

这样我就可以做(大致)这样的事情:

So that I can do things like (roughly):

template<typename T, size_t X, size_t Y>
void sort2(T(&arr)[X][Y])
{
    T *p = reinterpret_cast<T *>(&arr);
    std::sort(p, p + X*Y);
}

演示: https://ideone.com/tlm190

据我所知,该标准保证2D数组的对齐在内存中是连续的,尽管p + X*Y从技术上讲是超出范围的,但从未访问过,因此也不会导致未定义行为.

To my knowledge, the standard guarantees that alignment of 2D array would be contiguous in memory, and although p + X*Y technically is out of range is never accessed so should not lead to Undefined Behaviour either.

需要时,我可以绝对将2D数组视为1D数组吗?

Can I absolutely treat 2D arrays as 1D arrays when needed?

推荐答案

谢谢大家的答复和评论,但我认为正确的答案是-尽管它可以纠正,但它代表了技术性UB.我已经浏览了其中的一些问题[ 1 2 ] @xskxzr链接了,这使我想到了标准中的这句话:

Thank you all for replying and commenting, but I think the correct answer is - as it stands the code exhibits technical UB, though correctable. I have looked through some of those questions [1, 2] @xskxzr linked and it led me to this quote from the standard:

如果两个对象是指针可互换的,则它们具有相同的 地址,并且有可能从指针获得指向一个的指针 通过 reinterpret_cast 彼此联系. [注意:一个数组对象及其 第一个元素不是指针可互换的,即使它们具有 相同的地址. — 尾注]

If two objects are pointer-interconvertible, then they have the same address, and it is possible to obtain a pointer to one from a pointer to the other via a reinterpret_­cast. [ Note: An array object and its first element are not pointer-interconvertible, even though they have the same address. — end note ]

然后在 reinterpret_cast页面上,有以下注释举个例子:

Then on reinterpret_cast page there is the following note with an example:

假设满足对齐要求,则 reinterpret_cast 在少数情况下不更改指针的值 处理 pointer-interconvertible 对象:

Assuming that alignment requirements are met, a reinterpret_cast does not change the value of a pointer outside of a few limited cases dealing with pointer-interconvertible objects:

int arr[2];
int* p5 = reinterpret_cast<int*>(&arr); // value of p5 is unchanged by reinterpret_cast and
                                        // is "pointer to arr"

即使此无需警告即可编译并运行,从技术上讲,这是一种UB,因为从技术上讲p5仍然是指向arr而不是arr[0]的指针.因此,基本上,按照我使用reinterpret_cast的方式使用它会导致UB.考虑到上述情况,如果我直接在第一个int上创建int *(根据@codekaizer的回答,这没关系),那么这应该是正确的,对吧?:

Even though this compiles without warning and runs, this is technically a UB because p5 is technically still a pointer to arr and not to arr[0]. So basically the use of reinterpret_cast the way I used it leads to UB. Taking the above into account, if I were to create int * directly to the 1st int (and this is ok according to the answer by @codekaizer), then this should be valid, right?:

template<typename T, size_t X, size_t Y>
void sort2(T(&arr)[X][Y])
{
    T *p = &arr[0][0]; // or T *p = arr[0];
    std::sort(p, p + X * Y);
}

但是它也可能是UB,因为指针p指向具有Y元素的T s第一个数组的第一个T. p + X*Y因此将指向该T的第一个数组的范围,因此是UB(再次感谢@xskxzr的

But it probably is UB as well since the pointer p is pointing to the first T of the first array of Ts which has Y elements. p + X*Y therefore will be pointing out of range of this 1st array of Ts, hence UB (thanks again to @xskxzr for the link and comment).

如果表达式P指向具有n的数组对象x的元素x [i] 元素,表达式P + J和J + P(其中J的值为j) 如果0≤i+j≤n,则指向(可能是假设的)元素x [i + j]; 否则,行为是不确定的.

If the expression P points to element x[i] of an array object x with n elements, the expressions P + J and J + P (where J has the value j) point to the (possibly-hypothetical) element x[i+j] if 0≤i+j≤n; otherwise, the behavior is undefined.

这是我放弃前的最后尝试:

So here is my final attempt before I give up:

template<typename T, size_t X, size_t Y>
void sort2(T(&arr)[X][Y])
{
    T(&a)[X * Y] = reinterpret_cast<T(&)[X * Y]>(arr);
    std::sort(a, a + X * Y);
}

在这里T arr[X][Y]首先使用reinterpret_cast再次转换为T a[X*Y],我认为这现在是有效的.重新解释的数组a愉快地衰减为指向数组a[X*Y]的第一个元素的指针(a + X * Y也在范围内),并转换为std::sort中的迭代器.

Here T arr[X][Y] is first converted to T a[X*Y] with, again, reinterpret_cast, which I think is now valid. The reinterpreted array a happily decays to a pointer to 1st element of array a[X*Y] (a + X * Y is also within the range) and gets converted to an iterator in std::sort.

TL; DR版本

行为未定义.将2D数组转换为1D数组的正确方法是:

Behaviour in the OP is Undefined because of improper use of reinterpret_cast. The correct way to convert 2D array to 1D array would be:

//-- T arr2d[X][Y]
T(&arr1d)[X*Y] = reinterpret_cast<T(&)[X*Y]>(arr2d);

可以将类型T1的左值表达式转换为对 另一类型的T2.结果是一个左值或x值,引用了 与原始左值相同的对象,但类型不同.不 创建临时文件,不创建副本,不构造函数或进行转换 函数被调用.结果参考只能访问 如果类型别名规则允许,则可以安全地

An lvalue expression of type T1 can be converted to reference to another type T2. The result is an lvalue or xvalue referring to the same object as the original lvalue, but with a different type. No temporary is created, no copy is made, no constructors or conversion functions are called. The resulting reference can only be accessed safely if allowed by the type aliasing rules

别名规则:

每当尝试读取或修改存储的值时, 动态类型类型的对象通过AliasedType类型的glvalue, 除非满足以下条件之一,否则行为是不确定的:

Whenever an attempt is made to read or modify the stored value of an object of type DynamicType through a glvalue of type AliasedType, the behavior is undefined unless one of the following is true:

  • AliasedType和DynamicType相似.

类型相似:

非正式地,如果忽略顶层,则两种类型是相似的 简历资格

Informally, two types are similar if, ignoring top-level cv-qualification

  • 它们都是相同大小的数组,或者都是边界未知的数组,并且数组元素类型相似.

数组元素类型:

在声明T D中,其中D具有形式

In a declaration T D where D has the form

D1 [ constant-expression opt ] attribute-specifier-seq opt

,声明T D1中标识符的类型为 " derived-declarator-type-list T",则D的标识符的类型为数组类型;如果D标识符的类型包含自动的 type-specifier ,则程序格式错误. T称为数组元素类型;

and the type of the identifier in the declaration T D1 is "derived-declarator-type-list T", then the type of the identifier of D is an array type; if the type of the identifier of D contains the auto type-specifier, the program is ill-formed. T is called the array element type;

这篇关于将2D数组视为1D数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆