Name | Description | Notes | Source | Availability | |||||||
---|---|---|---|---|---|---|---|---|---|---|---|
offsetof() |
Determine structure-member position | L | M | (·) | <stddef.h> |
C89 | C90 | C95 | C99 | C11 | |
struct |
Introduces structure type | L | Keyword | C89 | C90 | C95 | C99 | C11 |
C allows groups of related objects to
be handled as a unit called a structure. The
keyword struct
introduces a structure type which can then be used
to declare objects of that type. For
example, the following declaration defines a new type called
struct
point
, which has two members, x
and y
, both of type
int
:
struct point { int x; int y; };
The name of the type is struct
point
, not point
, which is just
the type's tag, and could safely identify another
object or a distinct type.
Members of a structure type can be of any complete type. With the
above declaration in place, variables now can be declared of
type struct
point
, and individual members can be accessed using
the operator .
:
struct point a, b;
a.x = 10;
a.y = 20;
b.x = -a.y;
b.y = a.x;
- postfix-expression
-
postfix-expression . identifier
Structures and Unions
It's also possible to list initial values for a structure when it is defined:
struct point a = { 10, 20 }; struct point b = { -a.y, a.x };
It is an error if there are more values than members. If there are too few, remaining members are zero-initialized. From C99, specific members can be initialized in any order:
struct point a = { .x = 10, .y = 20 }; struct point b = { .y = a.x, .x = -a.y };
Structures can be passed to and returned from functions:
struct point add_points(struct point p1, struct point p2) { p1.x += p2.x; p1.y += p2.y; return p1; }
As parameters, they are ordinary copies of whatever was passed to them, so it is safe for the function to modify its own copies, as above. However, structures can be very large, and passing copies of them as function arguments, and returning them too, can incur a large overhead. Therefore, it is very common to see them passed by reference using a pointer. For example, this function would usually be considered more efficient than the one above:
void add_points(struct point *out, struct point *p1, struct point *p2) { (*out).x = (*p1).x + (*p2).x; (*out).y = (*p1).y + (*p2).y; }
Note that the pointer-dereference operator *
has lower precedence than the member-access
operator .
, so additional brackets are
necessary. Because structures are almost always used with
pointers, another operator is provided ->
, which combines the dereferencing and member
access in one. This allows us to rewrite the function more
aesthetically:
void add_points(struct point *out, struct point *p1, struct point *p2) { out->x = p1->x + p2->x; out->y = p1->y + p2->y; }
- postfix-expression
-
postfix-expression -> identifier
Structures and Unions
As the function does not and should not modify its inputs,
we can use const
on them:
void add_points(struct point *out, const struct point *p1, const struct point *p2) { out->x = p1->x + p2->x; out->y = p1->y + p2->y; }
The definition of a structure type can be combined with a declaration of an object of that type:
struct point { int x; int y; } p1, p2, p3;
In fact, a structure-type definition is an object declaration, but object declarations need not actually declare any objects. This means that the following declaration is not only bizarre and pointless, but also legal!:
int;
Objects can be of anonymous structure type too. This is useful in a few circumstances. One is when declaring an object with the type definition:
struct { double length; int counter; // etc. } foo;
Such an object obviously can't be passed to a function without losing its type information.
Another use of an anonymous type is with a type alias, such as:
typedef struct { int x; int y; } point;
As with all typedef
s, the new type name sits where a
variable name would be if the typedef
keyword were to be removed. This
structure type is innately anonymous, but the alias will work
as expected, allowing us to declare functions more
compactly:
void add_points(point *out, const point *p1, const point *p2)
The structure types shown so far are all complete. As such, you can declare arrays of structures, unions of structures, and even structures of structures. For example:
struct rect { struct point min, max; };
So it's not uncommon for members of a named structure type to be of anonymous types, used only for grouping related members together.
Structure types can be incomplete too:
struct point;
This is sufficient to declare something that uses pointers to the structure type:
// okay void add_points(struct point *out, const struct point *p1, const struct point *p2)
…but not something that depends on the whole structure, such as that function's definition, or a declaration of the alternative function that doesn't use pointers:
// error struct point add_points(struct point p1, struct point p2);
In such cases, the complete structure type must first be visible. It's legal to declare an incomplete type, and then complete it later:
struct point; // Okay struct point { int x, y; };
It is illegal to complete the type twice in the same translation unit, even if the definitions are identical:
// Okay struct point { int x, y; }; // Error struct point { int x, y, z; }; // Error struct point { int x, y; };
An incomplete structure type also can't appear directly in its own definition:
struct foo { struct foo inner; // error };
The definition of struct
foo
is incomplete until the end of its definition, so
it can't be used until after the closing brace }
. In any case, this recursive definition would
imply that the structure had infinite size! An alternative
using pointers is permitted:
struct elem { struct elem *next; char *text; };
…because struct elem
*
is a complete type, even if struct
elem
is not (yet). Such structure types are commonly
used to form complex data structures (in the more general
sense of ‘structure’) such as linked lists and binary
trees.
From C99, a structure type can end with a member of array type with unspecified length. For example:
struct foo { int bar; double baz; size_t sz; T buff[]; };
The size of a structure of this type
with n trailing elements is given by sizeof(struct foo) +
n * sizeof(T)
, for any complete type
T
.
The alignment of members of a structure type can be
configured with alignas
.
If a structure has an address, then each of its members can have an
address too. The address-of operator &
has lower precedence than .
or ->
, so an
expression such as &p1->x
will
give us the address of the member x
as
expected.
#include <stddef.h>
size_t offsetof(struct-type, struct-member);
The macro offsetof
will give the relative position of a structure member within
its type, e.g.,
offsetof(struct
point, y)
.
Structure types can include bitfields, integer members of a specific width. For example:
struct header { unsigned type : 4; unsigned route : 1, urgent : 1, ext : 1; };
Such bitfields do not have addresses. How they pack into
the underlying bytes of the
structure, including their order and padding, is implementation-defined. A bitfield of
width 0
, which can also be anonymous,
can indicate that the next member should be aligned on some
implementation-defined boundary.
Structures are often dynamically allocated:
struct point *ptr = malloc(sizeof *ptr);
Such a structure must be deallocated as a unit too:
free(ptr);
It's not possible to deallocate an individual member of a structure:
free(&ptr->y); // error
Name | Description | Notes | Source | Availability | |||||||
---|---|---|---|---|---|---|---|---|---|---|---|
div_t |
Result of integer division | T | <stdlib.h> |
C89 | C90 | C95 | C99 | C11 | |||
imaxdiv_t |
Result of integer division | T | <inttypes.h> |
C99 | C11 | ||||||
ldiv_t |
Result of integer division | T | <stdlib.h> |
C99 | C11 | ||||||
lldiv_t |
Result of integer division | T | <stdlib.h> |
C99 | C11 | ||||||
struct
lconv |
Description of local notations | T | <locale.h> |
C89 | C90 | C95 | C99 | C11 | |||
struct
timespec |
Nanosecond time type | T | <time.h> |
C11 | |||||||
struct tm |
Time type | T | Headers | C89 | C90 | C95 | C99 | C11 |
- type-specifier
struct-or-union-specifier
- struct-or-union-specifier
struct-or-union identifieropt { struct-declaration-list }
struct-or-union identifier
- struct-or-union
struct
- struct-declaration-list
struct-declaration
struct-declaration-list struct-declaration
- struct-declaration
specifier-qualifier-list struct-declarator-listopt ;
-
static_assert-declaration
since C11 - specifier-qualifier-list
type-specifier specifier-qualifier-listopt
type-qualifier specifier-qualifier-listopt