Alex Celeste
Alex Celeste

Reputation: 13370

Can an array have trailing padding?

It is clear that arrays in C cannot insert padding between their elements. However, is there any rule saying that they can't add trailing padding at the end of the array as a whole?

i.e. is this program guaranteed to give the same results everywhere?

#include <stdio.h>
int main(void) {
    typedef char a[3];
    typedef a b[3];
    printf("%zu %zu\n", sizeof(a), sizeof(b)); // -> 3 9
}

As far as I can work out, adding a trailing byte or five to the size of a, perhaps in a misguided optimization attempt, wouldn't break the array access rules (b[1][1] still maps exactly to *(&b + sizeof(a) * 1 + 1) regardless of the size of its contained a objects, and accessing beyond the length of a contained a is UB anyway).

I can't find anywhere in the C standard where it actually says outright that the size of an array is the size of the element type multiplied by the number of elements. 6.5.3.4 only says that sizeof returns the "number of bytes" in the array (it does give sizeof array / sizeof array[0] as a code example, but it's only an example - it doesn't say it has to work, and it doesn't give any details).

The implicit guarantee is useful for writing portable code that depends on exact data layouts, e.g. passing packed RGB values:

typedef uint8_t RGB[3];
RGB * data = ...;
glColorPointer(3, GL_UNSIGNED_BYTE, 0, data);

(OK so OpenGL can accept stride values so this is a bad example, but you get the point)

For that matter, I assume from the widespread notion (even to the example in the standard) that you can get the number of elements of an array with sizeof, that this is likely to hold true everywhere anyway - are there any known situations where it isn't?

Upvotes: 6

Views: 864

Answers (1)

user743382
user743382

Reputation:

I believe it was never considered necessary for the standard to actually spell out that arrays don't have padding, for the simple reason that there is absolutely no reason why such padding might ever be useful on any implementation.

That said, I do believe the standard forbids such padding, through the description of the == operator.

6.5.9 Equality operators

Semantics

6 Two pointers compare equal if and only if [...] or one is a pointer to one past the end of one array object and the other is a pointer to the start of a different array object that happens to immediately follow the first array object in the address space.

Given

int array[2][2];

the expression &array[0][2] points is a pointer one past the end of the first array subobject. &array[1][0] is a pointer to the second array subobject, which immediately follows the first array in memory. These pointers are required to compare equal. If int[2] had trailing padding, if sizeof(int[2]) > 2 * sizeof(int), I cannot imagine how any implementation could make the two pointers compare as equal.

Upvotes: 6

Related Questions