Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Casting double* to double(*)[N]

Tags:

arrays

c

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);
}

Sometimes, it'd be very convenient to treat a parameter as a multi-dimensional array, but it needs to be declared as a pointer into a flat array. Is it safe to cast the pointer to treat it as a multidimensional array, as compute does in the above example? I'm pretty sure the memory layout is guaranteed to work correctly, but I don't know if the standard allows pointers to be cast this way.

Does this break any strict aliasing rules? What about the rules for pointer arithmetic; since the data "isn't actually" a double[5][5], are we allowed to perform pointer arithmetic and indexing on data2D, or does it violate the requirement that pointer arithmetic not stray past the bounds of an appropriate array? Is data2D even guaranteed to point to the right place, or is it just guaranteed that we can cast it back and recover data? Standard quotes would be much appreciated.

like image 770
user2357112 supports Monica Avatar asked Feb 28 '14 11:02

user2357112 supports Monica


1 Answers

I apologize in advance for a somewhat vague answer, as someone said these rules in the standard are quite hard to interpret.

C11 6.3.2.3 says

A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined.

So the actual cast is fine, as long as both pointers have the same alignment.

And then regarding accessing the actual data through the pointer, C11 6.5 gives you a wall of gibberish text regarding "aliasing", which is quite hard to understand. I'll try to cite what I believe are the only relevant parts for this specific case:

"The effective type of an object for an access to its stored value is the declared type of the object, if any." /--/

"An object shall have its stored value accessed only by an lvalue expression that has one of the following types:

  • a type compatible with the effective type of the object, "

/--/

  • "an aggregate or union type that includes one of the aforementioned types among its members"

(The above is sometimes referred to as the "strict aliasing rule", which isn't a formal C language term, but rather a term made up by compiler implementers.)

In this case, the effective type of the object is an array of 25 doubles. You are attempting to cast it to an array pointer to an array of 5 doubles. Whether it counts as a type compatible with the effective type, or as an aggregate which includes the type, I'm not sure. But I'm quite sure it counts as either of those two valid cases.

So as far as I can see, this code doesn't violate 6.3.2.3 nor 6.5. I believe that the code is guaranteed to work fine and the behavior should be well-defined.

like image 117
Lundin Avatar answered Nov 16 '22 13:11

Lundin