sizeof() and a structure

S

srikar2097

This question is to know more about the internals of C. Lets assume a
structure -

struct node
{
int data;
struct node *next;
};

When we apply the sizeof() operator to this we do not get the size
occupied by the elements of this structure. Eg. here sizeof(node) $B!b(B
sizeof(data) + sizeof(*next);
it usually is greater than the summation of the size occupied by the
elements inside a struct. Where is the extra space going's?

Thanks in advance..
 
U

user923005

This question is to know more about the internals of C. Lets assume a
structure -

struct node
{
int data;
struct node *next;

};

When we apply the sizeof() operator to this we do not get the size
occupied by the elements of this structure. Eg. here sizeof(node) $B!b(B
sizeof(data) + sizeof(*next);
it usually is greater than the summation of the size occupied by the
elements inside a struct. Where is the extra space going's?

It's a FAQ.

From the C-FAQ:
2.12: My compiler is leaving holes in structures, which is wasting
space and preventing "binary" I/O to external data files. Why?
Can I turn this off, or otherwise control the alignment of
structure fields?

A: Those "holes" provide "padding", which may be needed in order to
preserve the "alignment" of later fields of the structure. For
efficient access, most processors prefer (or require) that
multibyte objects (e.g. structure members of any type larger
than char) not sit at arbitrary memory addresses, but rather at
addresses which are multiples of 2 or 4 or the object size.

Your compiler may provide an extension to give you explicit
control over struct alignment (perhaps involving a #pragma; see
question 11.20), but there is no standard method.

See also question 20.5.

References: K&R2 Sec. 6.4 p. 138; H&S Sec. 5.6.4 p. 135.

2.13: Why does sizeof report a larger size than I expect for a
structure type, as if there were padding at the end?

A: Padding at the end of a structure may be necessary to preserve
alignment when an array of contiguous structures is allocated.
Even when the structure is not part of an array, the padding
remains, so that sizeof can always return a consistent size.
See also question 2.12 above.

References: H&S Sec. 5.6.7 pp. 139-40.

Some compilers allow you to align structures with little or no padding
bytes, but there is a performance cost for doing this and it is not
fully portable.
 
M

Martin Ambuhl

srikar2097 said:
This question is to know more about the internals of C. Lets assume a
structure -

struct node
{
int data;
struct node *next;
};

When we apply the sizeof() operator to this we do not get the size
occupied by the elements of this structure.

Yes, you do.
Eg. here sizeof(node) ≠
sizeof(data) + sizeof(*next);

There is no reason to suppose that the size of a struct node is
sizeof(data) + sizeof(*next).
You have made a completely unwarranted assumption.
The size of an object is _at least_ the sum of the sizes of the named
parts of it.
it usually is greater than the summation of the size occupied by the
elements inside a struct. Where is the extra space going's?

Usually to padding. This is covered in all elementary C texts (and in
the FAQ, which you should have checked before posting).
Thanks in advance..

Another user of bill-collector language.
 
K

Keith Thompson

Jujitsu Lizard said:
Generally speaking, any structure is going to be aligned (i.e. start)
on the least restrictive type of address that the machine has
(typically an address that is a multiple of 4 or 8). This will often
be an address returned by malloc() and friends.

Not necessarily. If none of a structure's members require large
alignment, the structure itself won't necessarily require large
alignment. The compiler is free to align all structures on, say,
4-byte or 8-byte boundaries, but it's not required to.

A concrete example: this structure:
struct c { char c; };
has 1-byte alignment under gcc, and if you declare adjacent two
objects of this type, one of them will probably have an odd address.
You can typically minimize the padding by arranging the structure
members from largest to smallest. This tends to work because any
address suitable for, for example, a 32-bit integer also tends to be
suitable for a 16-bit integer, and any address suitable for a 16-bit
integer is suitable for a character.

To give an example:

struct memorywaster {
char c[3];
short a, b, c;
int x, y, z;
long p, d, q;
};

If you really want to waste memory, though, don't put members of the
same type together. Preceding each long by a char will typically
require sizeof(long)-1 bytes of padding.
If you put the members in the reverse order, a compiler will typically
use padding only at the end.

Typically, yes, but the standard doesn't forbid arbitrary extra
padding.
I do not know if a compiler is required to order structure members in
memory in the same order they are declared. I just know that the
compilers I've seen do.

Yes, the standard requires this.
 
U

user923005

[...]
Generally speaking, any structure is going to be aligned (i.e. start)
on the least restrictive type of address that the machine has
(typically an address that is a multiple of 4 or 8).  This will often
be an address returned by malloc() and friends.

Not necessarily.  If none of a structure's members require large
alignment, the structure itself won't necessarily require large
alignment.  The compiler is free to align all structures on, say,
4-byte or 8-byte boundaries, but it's not required to.

A concrete example: this structure:
    struct c { char c; };
has 1-byte alignment under gcc, and if you declare adjacent two
objects of this type, one of them will probably have an odd address.
You can typically minimize the padding by arranging the structure
members from largest to smallest.  This tends to work because any
address suitable for, for example, a 32-bit integer also tends to be
suitable for a 16-bit integer, and any address suitable for a 16-bit
integer is suitable for a character.
To give an example:
struct memorywaster {
char c[3];
short a, b, c;
int x, y, z;
long p, d, q;
};

If you really want to waste memory, though, don't put members of the
same type together.  Preceding each long by a char will typically
require sizeof(long)-1 bytes of padding.

e.g.:

#include <stdio.h>
#include <stddef.h>

typedef struct tragic_stupid {
char a;
unsigned long long b;
char c;
unsigned long long d;
char e;
unsigned long long f;
char g;
unsigned long long h;
char i;
unsigned long long j;
char k;
unsigned long long l;
char m;
unsigned long long n;
} badly_aligned_thingy;

int main(void)
{
printf("badly_aligned_thingy.a is at %u\n", offsetof
(badly_aligned_thingy, a));
printf("badly_aligned_thingy.b is at %u\n", offsetof
(badly_aligned_thingy, b));
printf("badly_aligned_thingy.c is at %u\n", offsetof
(badly_aligned_thingy, c));
printf("badly_aligned_thingy.d is at %u\n", offsetof
(badly_aligned_thingy, d));
printf("badly_aligned_thingy.e is at %u\n", offsetof
(badly_aligned_thingy, e));
printf("badly_aligned_thingy.f is at %u\n", offsetof
(badly_aligned_thingy, f));
printf("badly_aligned_thingy.g is at %u\n", offsetof
(badly_aligned_thingy, g));
printf("badly_aligned_thingy.h is at %u\n", offsetof
(badly_aligned_thingy, h));
printf("badly_aligned_thingy.i is at %u\n", offsetof
(badly_aligned_thingy, i));
printf("badly_aligned_thingy.j is at %u\n", offsetof
(badly_aligned_thingy, j));
printf("badly_aligned_thingy.k is at %u\n", offsetof
(badly_aligned_thingy, k));
printf("badly_aligned_thingy.l is at %u\n", offsetof
(badly_aligned_thingy, l));
printf("badly_aligned_thingy.m is at %u\n", offsetof
(badly_aligned_thingy, m));
printf("badly_aligned_thingy.n is at %u\n", offsetof
(badly_aligned_thingy, n));
return 0;
}
/* One possible output:
badly_aligned_thingy.a is at 0
badly_aligned_thingy.b is at 8
badly_aligned_thingy.c is at 16
badly_aligned_thingy.d is at 24
badly_aligned_thingy.e is at 32
badly_aligned_thingy.f is at 40
badly_aligned_thingy.g is at 48
badly_aligned_thingy.h is at 56
badly_aligned_thingy.i is at 64
badly_aligned_thingy.j is at 72
badly_aligned_thingy.k is at 80
badly_aligned_thingy.l is at 88
badly_aligned_thingy.m is at 96
badly_aligned_thingy.n is at 104
*/
 
K

Keith Thompson

user923005 said:
To give an example:
struct memorywaster {
char c[3];
short a, b, c;
int x, y, z;
long p, d, q;
};

If you really want to waste memory, though, don't put members of the
same type together.  Preceding each long by a char will typically
require sizeof(long)-1 bytes of padding.

e.g.:

#include <stdio.h>
#include <stddef.h>

typedef struct tragic_stupid {
char a;
unsigned long long b; [..]
} badly_aligned_thingy;

int main(void)
{
printf("badly_aligned_thingy.a is at %u\n", offsetof
(badly_aligned_thingy, a));
printf("badly_aligned_thingy.b is at %u\n", offsetof
(badly_aligned_thingy, b)); [...]
return 0;
}
/* One possible output:
badly_aligned_thingy.a is at 0
badly_aligned_thingy.b is at 8
badly_aligned_thingy.c is at 16
badly_aligned_thingy.d is at 24
badly_aligned_thingy.e is at 32
badly_aligned_thingy.f is at 40
badly_aligned_thingy.g is at 48
badly_aligned_thingy.h is at 56
badly_aligned_thingy.i is at 64
badly_aligned_thingy.j is at 72
badly_aligned_thingy.k is at 80
badly_aligned_thingy.l is at 88
badly_aligned_thingy.m is at 96
badly_aligned_thingy.n is at 104
*/
[...]

Except that offsetof() yields a result of type size_t, which isn't
necessarily compatible with unsigned int. Assuming C99, you can use
"%zu" rather than "%u"; otherwise, you can cast to unsigned long and
use "%lu".
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,185
Members
46,736
Latest member
AdolphBig6

Latest Threads

Top