Is it guaranteed that array elements in C will be stored consecutively, with no padding?

╄→尐↘猪︶ㄣ 提交于 2020-01-04 02:02:26

问题


In other words: is it guaranteed that if I have an array allocated this way:

void *arr = calloc(nmemb, sizeof(some_type))

Then elta, eltb, eltc will all point to the same location in memory, which will be the second element of type some_type of this array?

some_type *elta = &((some_type*)arr)[1];
some_type *eltb = ((some_type*)arr)+1;
some_type *eltc = (char*)arr+sizeof(some_type);

The reason I’m asking this is because I’m trying to do a “container” in C, and if this doesn’t hold then I’m out of ideas how to return a pointer to any other element than the first one.


回答1:


Yes, it is guaranteed. If padding bytes are added, they are added within struct some_type, but not in between two array elements.

E. g.:

struct S
{
    int n;
    short s;

// this is just for illustration WHERE byte padding (typically) would occur!!!
#if BYTE_ALIGNMENT >= 4
    unsigned char : 0;
    unsigned char : 0;
#endif
};
struct S s[2];
size_t d = (char*)(s + 1) - (char*)s;

With byte alignment adjusted to 4 or 8 (or even larger powers of 2), this struct will have size of 8 and d will be equally 8, with byte alignment set to 1 or 2, the struct will have size of 6 just as will be d...

Note: This is not the only place where padding bytes can occur: If you switched members n and s, padding bytes would be needed in between s and n to get n correctly aligned. On the other hand, no padding bytes would be necessary after n any more as the structure size would assure correct alignment already.

Referring to the standard: C11, 6.2.5.20:

An array type describes a contiguously allocated nonempty set of objects with a particular member object type, called the element type. 36) Array types are characterized by their element type and by the number of elements in the array. [...]

(Highlighting by me!).




回答2:


Data alignment is a complex matter, as illustrated by the following example (that you can even draw to make your own experiments):

#include <stdio.h>
struct A {  /* no padding */
    char a[3];
};
struct B {
    int  a;
    char b[3];
    /* one byte of padding (in 32bit arch) added here */
};
struct C {  /* no padding again */
    char a[4];
    char b[3];
};

struct D {
    char a[3];
    /* one byte of padding to ensure alignment of next field */
    int  b;
    char c[3];
    /* one byte of padding to ensure alignment of whole struct in arrays */
}

#define P(X) printf("sizeof struct %s == %ld\n", #X, sizeof (struct X))
int main()
{
    P(A);
    P(B);
    P(C);
    P(D);
} /* main */

As you see, the required alignment (1 byte) of the struct A type is allowing to place it anywhere in memory and determines that no padding bytes are necessary to determine the sizeof value.

In the second example, we introduced an int value, which forces the whole struct to be word aligned (so an int is accessible in a properly aligned memory address) so this time, the compiler has padded (at the end of the structure) for extra bytes, so any array type of the specified type gets correctly aligned, and its int field is accessed at a valid address.

In the third example, I illustrate that the effect of the padding in the second example is due to the int field present in the struct, as the third example has a same size field, but this time a non requiring alignment field, so no padding has been inserted, as all the individual data types inside need alignment of 1.

The output (on my system, a MAC OSX system) is:

sizeof struct A == 3
sizeof struct B == 8
sizeof struct C == 7
sizeof struct D == 12


来源:https://stackoverflow.com/questions/43766161/is-it-guaranteed-that-array-elements-in-c-will-be-stored-consecutively-with-no

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!