A “structure declaration” names a type and specifies a sequence of variable values (called “members” or “fields” of the structure) that can have different types. An optional identifier, called a “tag,” gives the name of the structure type and can be used in subsequent references to the structure type. A variable of that structure type holds the entire sequence defined by that type. Structures in C are similar to the types known as “records” in other languages.
struct-or-union-specifier :
struct-or-union identifier opt { struct-declaration-list }
struct-or-union identifier
struct-or-union :
struct
union
struct-declaration-list :
struct-declaration
struct-declaration-list struct-declaration
The structure content is defined to be
struct-declaration :
specifier-qualifier-list struct-declarator-list ;
specifier-qualifier-list :
type-specifier specifier-qualifier-list opt
type-qualifier specifier-qualifier-list opt
struct-declarator-list :
struct-declarator
struct-declarator-list , struct-declarator
struct-declarator :
declarator
The declaration of a structure type does not set aside space for a structure. It is only a template for later declarations of structure variables.
A previously defined identifier (tag) can be used to refer to a structure type defined elsewhere. In this case, struct-declaration-list cannot be repeated as long as the definition is visible. Declarations of pointers to structures and typedefs for structure types can use the structure tag before the structure type is defined. However, the structure definition must be encountered prior to any actual use of the size of the fields. This is an incomplete definition of the type and the type tag. For this definition to be completed, a type definition must appear later in the same scope.
The struct-declaration-list specifies the types and names of the structure members. A struct-declaration-list argument contains one or more variable or bit-field declarations.
Each variable declared in struct-declaration-list is defined as a member of the structure type. Variable declarations within struct-declaration-list have the same form as other variable declarations discussed in this chapter, except that the declarations cannot contain storage-class specifiers or initializers. The structure members can have any variable types except type void, an incomplete type, or a function type.
A member cannot be declared to have the type of the structure in which it appears. However, a member can be declared as a pointer to the structure type in which it appears as long as the structure type has a tag. This allows you to create linked lists of structures.
Structures follow the same scoping as other identifiers. Structure identifiers must be distinct from other structure, union, and enumeration tags with the same visibility.
Each struct-declaration in a struct-declaration-list must be unique within the list. However, identifier names in a struct-declaration-list do not have to be distinct from ordinary variable names or from identifiers in other structure declaration lists.
Nested structures can also be accessed as though they were declared at the file-scope level. For example, given this declaration:
struct a
}
int x;
struct b
{
int y;
} var2;
} var1;
these declarations are both legal:
struct a var3;
struct b var4;
These examples illustrate structure declarations:
struct employee /* Defines a structure variable named temp */
{
char name[20];
int id;
long class;
} temp;
The employee structure has three members: name, id, and class. The name member is a 20-element array, and id and class are simple members with int and long type, respectively. The identifier employee is the structure identifier.
struct employee student, faculty, staff;
This example defines three structure variables: student, faculty, and staff. Each structure has the same list of three members. The members are declared to have the structure type employee, defined in the previous example.
struct /* Defines an anonymous struct and a
{ structure variable named complex */
float x, y;
} complex;
The complex structure has two members with float type, x and y. The structure type has no tag and is therefore unnamed or anonymous.
struct sample /* Defines a structure named x */
{
char c;
float *pf;
struct sample *next;
} x;
The first two members of the structure are a char variable and a pointer to a float value. The third member, next, is declared as a pointer to the structure type being defined ( sample ).
Anonymous structures can be useful when the tag named is not needed. This is the case when one declaration defines all structure instances. For example:
struct
{
int x;
int y;
} mystruct;
Embedded structures are often anonymous.
struct somestruct
{
struct /* Anonymous structure */
{
int x, y;
} point;
int type;
} w;
Microsoft Specific
The compiler allows an unsized or zero-sized array as the last member of a structure. This can be useful if the size of a constant array differs when used in various situations. The declaration of such a structure looks like this:struct identifier
{
set-of-declarations
type array_name[ ];
};
Unsized arrays can appear only as the last member of a structure. Structures containing unsized array declarations can be nested within other structures as long as no further members are declared in any enclosing structures. Arrays of such structures are not allowed. The sizeof operator, when applied to a variable of this type or to the type itself, assumes 0 for the size of the array.
Structure declarations can also be specified without a declarator when they are members of another structure or union. The field names are promoted into the enclosing structure. For example, a nameless structure looks like this:
struct s
{
float y;
struct
{
int a, b, c;
};
char str[10];
} *p_s;
.
.
.
p_s->b = 100; /* A reference to a field in the s structure */
See “Structure and Union Members” for information about structure references.¨
In addition to declarators for members of a structure or union, a structure declarator can also be a specified number of bits, called a “bit field.” Its length is set off from the declarator for the field name by a colon. A bit field is intepreted as an integral type.
struct-declarator :
declarator
type-specifier declarator opt : constant-expression
The constant-expression specifies the width of the field in bits. The type-specifier for the declarator must be unsigned int, signed int, or int, and the constant-expression must be a nonnegative integer value. If the value is zero, the declaration has no declarator. Arrays of bit fields, pointers to bit fields, and functions returning bit fields are not allowed. The optional declarator names the bit field. Bit fields can only be declared as part of a structure. The address-of operator (&) cannot be applied to bit-field components.
Unnamed bit fields cannot be referenced, and their contents at run time are unpredictable. Unnamed bit fields can be used as “dummy” fields, for alignment purposes. An unnamed bit field whose width is specified as 0 guarantees that storage for the member following it in the struct-declaration list begins on an int boundary.
Bit fields must also be long enough to contain the bit pattern. For example, these two statements are not legal:
short a:17; /* Illegal! */
int long y:33; /* Illegal! */
This example defines a two-dimensional array of structures named screen.
struct
{
unsigned short icon : 8;
unsigned short color : 4;
unsigned short underline : 1;
unsigned short blink : 1;
} screen[25][80];
The array contains 2,000 elements. Each element is an individual structure containing four bit-field members: icon, color, underline, and blink. The size of each structure is two bytes.
Microsoft Specific
Bit fields defined as intare treated as signed. A Microsoft extension to the ANSI C standard allows charand longtypes (both signedand unsigned) for bit fields. Unnamed bit fields with base type long, short, or char(signedor unsigned) force alignment to a boundary appropriate to the base type.Bit fields are allocated within an integer from least-significant to most-significant bit. In the following code
struct mybitfields
{
unsigned short a : 4;
unsigned short b : 5;
unsigned short c : 7;
} test;
void main( void );
{
test.a = 2;
test.b = 31;
test.c = 0;
}
the bits would be arranged as follows:
00000001 11110010
cccccccb bbbbaaaa
Since the 8086 family of processors stores the low byte of integer values before the high byte, the integer 0x01F2 above would be stored in physical memory as 0xF2 followed by 0x01.¨
Storage and Alignment of Structures
Structure members are stored sequentially in the order in which they are declared: the first member has the lowest memory address and the last member the highest. Storage for each member begins on a memory boundary appropriate to its type. Therefore, unnamed spaces (“holes” or “padding”) can appear between structure members in memory. The bit patterns appearing in such holes are unpredictable and can differ from structure to structure, or over time within a single structure.
Structure members are aligned to the minimum of their own size or the current packing size. For 16-bit targets, the default packing size is 2. This default corresponds to the /Zp2 command-line option.
The default packing size is 4 for 32-bit targets.¨
Microsoft Specific
To conserve space, or to conform to existing data structures, you may want to store structures more or less compactly. The /Zp compiler option or the packpragma controls how structure data is “packed”into memory. For more information on pragmas, see “Pragma Directives”.Use the /Zp option to specify the same packing for all structures in a module. When you give the /Zp[n] option, where n is 1, 2, or 4, each structure member after the first is stored on n-byte boundaries, depending on the option you choose. If you use the /Zp option without an argument, structure members are packed on 1-byte boundaries.
On some processors, the /Zp option can result in slower program execution because of the time required to unpack structure members when they are accessed. For example, on an 8086 processor, this option can reduce efficiency if members with int or long type are packed in such a way that they begin on odd-byte boundaries.
To use the pack pragma to specify packing other than the packing specified on the command line for particular structures, give the pack( n ) pragma, where n is 1, 2, or 4, before structures that you want to pack differently. To reinstate the packing given on the command line, specify the following with no arguments.
#pragma pack( ) /* Enables packing specified on command line */
See Chapter 12 in Programming Techniques for more information on packing.
For 16-bit targets, bit fields default to size short, which can cross a byte boundary but not a 16-bit or 32-bit boundary. If the size and location of a bit field would cause it to overflow the current integer, the field is moved to the beginning of the next available integer. If a bit field is declared as a long, it can hold up to 32 bits. In either case, an individual field cannot cross a 16-or 32-bit boundary.¨
Bit fields default to size long for the 32-bit compiler.¨