Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it guaranteed that the type T[x][y] has the same memory layout as T[x*y] in C?

So far thought it is, but after I learned that the compiler may pad data to align it for architecture requirements for example I'm in doubt. So I wonder if a char[4][3] has the same memory layout as char[12]. Can the compiler put padding after the char[3] part to make it aligned so the whole array takes actually 16 bytes?

The background story that a function of a library takes a bunch of fixed length strings in a char* parameter so it expects a continuous buffer without paddig, and the string length can be odd. So I thought I declare a char[N_STRINGS][STRING_LENGTH] array, then conveniently populate it and pass it to the function by casting it to char*. So far it seems to work. But I'm not sure if this solution is portable.

like image 802
Calmarius Avatar asked Dec 13 '15 12:12

Calmarius


People also ask

What are the memory layouts used in arrays?

The elements of an array can be stored in column-major layout or row-major layout. For an array stored in column-major layout, the elements of the columns are contiguous in memory. In row-major layout, the elements of the rows are contiguous. Array layout is also called order, format, and representation.

Do arrays have padding?

No, there will never be padding in between elements of an array.


2 Answers

An array of M elements of type A has all its elements in contiguous positions in memory, without padding bytes at all. This fact is not depending on the nature of A.

Now, if A is the type "array of N elements having type T", then each element in the T-type array will have, again, N contiguous positions in memory. All these blocks of N objects of type T are, also, stored in contiguous positions.

So, the result, is the existence in memory of M*N elements of type T, stored in contiguous positions.

The element [i][j] of the array is stored in the position i*N+j.

like image 132
pablo1977 Avatar answered Sep 18 '22 19:09

pablo1977


Let's consider

T array[size]; 
array[0]; // 1

1 is formally defined as:

The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2)))

per §6.5.2.1, clause 2 taken from the standard C draft N1570. When applied to multi-dimensional arrays, «array whose elements are arrays», we have:

If E is an n-dimensional array (n ≥ 2) with dimensions i × j × ... × k, then E (used as other than an lvalue) is converted to a pointer to an (n − 1)-dimensional array with dimensions j × . . . × k.

Therefore, given E = T array[i][j] and S = array[i][j], S is first converted to a pointer to a one-dimensional array of size j, namely T (*ptr)[j] = &array[i].

If the unary * operator is applied to this pointer explicitly, or implicitly as a result of subscripting, the result is the referenced (n − 1)-dimensional array, which itself is converted into a pointer if used as other than an lvalue.

and this rule applies recursively. We may conclude that, in order to do so, the n-dimensional array must be allocated contiguously.

It follows from this that arrays are stored in row-major order (last subscript varies fastest).

in terms of logical layout.

Since char [12] has to be stored contiguously and so has to char [3][4], and since they have the same alignment, they should be compatible, despite they're technically different types.

like image 44
edmz Avatar answered Sep 21 '22 19:09

edmz