将double *转换为double(*)[N]

时间:2014-02-28 11:14:30

标签: c arrays casting

void compute(int rows, int columns, double *data) {
    double (*data2D)[columns] = (double (*)[columns]) data;
    // do something with data2D
}

int main(void) {
    double data[25] = {0};
    compute(5, 5, data);
}

有时,将参数视为多维数组非常方便,但需要将其声明为指向平面数组的指针。将指针视为多维数组是否安全,如上例中compute所做的那样?我很确定内存布局可以保证正常工作,但我不知道标准是否允许指针以这种方式进行转换。

这会破坏任何严格的别名规则吗?指针算法的规则怎么样;由于数据“实际上并不是”double[5][5],我们是否允许在data2D上执行指针算法和索引,或者是否违反了指针算法不会偏离适当数组范围的要求? data2D甚至可以保证指向正确的位置,还是只保证我们可以将其强制转换并恢复data?标准报价将非常受欢迎。

2 个答案:

答案 0 :(得分:1)

我提前道歉,因为有人说标准中的这些规则很难解释。

C11 6.3.2.3说

  

指向对象类型的指针可以转换为指向a的指针   不同的对象类型。如果结果指针不正确   对于引用的类型,行为是未定义的。

所以只要两个指针具有相同的对齐方式,实际的强制转换就可以了。

然后关于通过指针访问实际数据,C11 6.5为您提供了一个关于“别名”的乱码文本,这很难理解。我将试着引用我认为是这个具体案例的唯一相关部分:

  

“访问其存储值的对象的有效类型是   声明的对象类型,如果有的话。“/ - /

     

“对象的存储值只能由左值访问   具有以下类型之一的表达式:

     
      
  • 类型兼容   与对象的有效类型,“
  •   
     

/ - /

     
      
  • “包含其中一种上述类型的聚合或联合类型   成员“
  •   

(以上有时被称为“strict aliasing rule”,它不是正式的C语言术语,而是由编译器实现者组成的术语。)

在这种情况下,对象的有效类型是25个双精度数组。您正在尝试将其强制转换为指向5个双精度数组的数组指针。无论它是与有效类型兼容的类型,还是包含该类型的聚合,我都不确定。但我很确定这是两个有效案件中的任何一个。

据我所见,此代码不违反6.3.2.3和6.5。我相信代码可以保证工作正常,行为应该是明确的。

答案 1 :(得分:0)

在这种情况下最安全的方法是将元素保存在一个平面的1维数组中,但是以多维方式编写访问器方法以从该数组中读取和写入。

#include <stdio.h>
#include <string.h>

const int rowCount = 10;
const int columnCount = 10;

const int dataSize = rowCount*columnCount;
double data[dataSize];


void setValue( const int x, const int y, double value)
{
    if ( x>=0 && x<columnCount && y>=0 && y<rowCount) {
        data[x+y*columnCount] = value;
    }
}


double getValue( const int x, const int y )
{
    if ( x>=0 && x<columnCount && y>=0 && y<rowCount) {
        return data[x+y*columnCount];
    } else {
        return 0.0;
    }
}


int main()
{
    memset(data, 0, sizeof(double)*dataSize);
    // set a value
    setValue(5, 2, 12.0);
    // get a value
    double value = getValue(2, 7);

    return 0;
}

该示例使用仅用于简单的全局变量。您可以将数据数组作为附加参数传递给函数,也可以创建要使用的上下文。

在c ++中,您可以将数据容器包装到一个类中,并使用这两种方法作为访问方法。