6

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?

Community
  • 1
  • 1
Alex Celeste
  • 12,824
  • 10
  • 46
  • 89
  • the meaning of padding is to make data aligned up. in you case, i am sure all char array of 3 will have size of 3. but if you declare an int after, there may be 1 or 5 padding followed. a good c compiler won't do extra job the make it hard to predict. but if you are talking about portability, i think it's better to compile the code again in target platform or cross compile if the platform has a lot of difference. – Jason Hu Nov 23 '14 at 19:36
  • "and it doesn't give any details" -- It does say that computes the number of elements in the array. You're right that that's only an example, though, and that examples aren't normative. –  Nov 23 '14 at 19:39
  • One can indirectly deduce that arrays don't have such padding by looking at the subsequent clause: "When applied to an operand that has structure or union type, the result is the total number of bytes in such an object, including internal and trailing padding." – this explicit reference to padding in structures and unions, and the lack thereof in the case of arrays makes me believe that arrays can't have such padding in them. – The Paramagnetic Croissant Nov 23 '14 at 19:41
  • 1
    I can't imagine what the point of padding an array would be. The elements are properly aligned already. – ooga Nov 23 '14 at 19:43
  • The definition of array in C11 is "An array type describes a contiguously allocated nonempty set of objects with a particular member object type". It seems to me that that does not allow any wiggle room. – M.M Nov 23 '14 at 20:57
  • 1
    @ooga: In a language which didn't allow the sort of pointer manipulations that C does, array padding could be useful for "canaries": if a compiler pre-loads the space past an array with a known pattern of marker data, such data may be periodically inspected to ensure that no buffer overrun has occurred. Alternatively, on some systems, it may be possible to configure hardware traps on any attempts to overwrite the carry addresses, though such features are generally limited to troubleshooting purposes (since many platforms have a very limited number of traps available). – supercat Jul 29 '15 at 19:05

1 Answers1

6

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.