0% found this document useful (0 votes)
17 views

Chap8 10

Uploaded by

Melih Ozulu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
17 views

Chap8 10

Uploaded by

Melih Ozulu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 96

Chapter 10

C Structures, Unions, Bit Manipulation and


Enumerations

C How to Program, 8/e, GE

© 2016 Pearson Education, Ltd. All rights reserved.


10.1  Introduction

• Structures—sometimes referred to as
aggregates—are collections of related variables
under one name.
• Structures may contain variables of many
different data types—
– in contrast to arrays, which contain only
elements of the same data type.
• Structures are commonly used to define records
to be stored in files (see Chapter 11, C File
Processing).
© 2016 Pearson Education, Ltd. All rights reserved.
10.1  Introduction (Cont.)
• We’ll also discuss:
– typedefs—for creating aliases for previously defined
data types
– unions—derived data types like structures, but with
members that share the same storage space
– bitwise operators—for manipulating the bits of
integral operands
– bit fields—unsigned int or int members of structures
or unions for which you specify the number of bits in
which the members are stored, helping you pack
information tightly
– enumerations—sets of integer constants represented
by identifiers.
10.2  Structure Definitions

• Structures are derived data types:


– they’re constructed using objects of other types.
• Consider the following structure definition:
struct card {
char *face;
char *suit;
};
• Keyword struct introduces the structure definition.
• The identifier card is the structure tag, which names
the structure definition and is used with struct to
declare variables of the structure type—e.g., struct
card.
© 2016 Pearson Education, Ltd. All rights reserved.
10.2  Structure Definitions (Cont.)

• Variables declared within the braces of the


structure definition are the structure’s members.
• Members of the same structure type must have
unique names, but two different structure types
may contain members of the same name without
conflict (we’ll soon see why).
• Each structure definition must end with a
semicolon.
10.2  Structure Definitions (Cont.)

• The definition of struct card contains


members face and suit, each of type char *.
• Structure members;
– can be variables of the primitive data types
(e.g., int, float, etc.),
– or aggregates, such as arrays and other
structures.
• Structure members can be of many types.

© 2016 Pearson Education, Ltd. All rights reserved.


10.2  Structure Definitions (Cont.)

• For example, the following struct contains


character array members for an employee’s first
and last names, an unsigned int member for the
employee’s age, a char member that would
contain 'M' or 'F' for the employee’s gender and
a double member for the employee’s hourly
salary:,
struct employee {
char firstName[20];
char lastName[20];
unsigned int age;
char gender;
double hourlySalary;
};
© 2016 Pearson Education, Ltd. All rights reserved.
10.2.1  Self-Referential Structures
• A structure cannot contain an instance of itself.
• For example, a variable of type struct employee
cannot be declared in the definition for struct
employee.
• A pointer to struct employee, however, may be
included.
• For example,
• struct employee2 {
char firstName[20];
char lastName[20];
unsigned int age;
char gender;
double hourlySalary;
struct employee2 person; // ERROR
struct employee2 *ePtr; // pointer
};
• struct employee2 contains an instance of itself
(person), which is an error.
10.2  Structure Definitions (Cont.)
• struct employee2 {
char firstName[20];
char lastName[20];
unsigned int age;
char gender;
double hourlySalary;
struct employee2 person; // ERROR
struct employee2 *ePtr; // pointer
};

• Because ePtr is a pointer (to type struct employee2),


it’s permitted in the definition.
• A structure containing a member that’s a pointer to the
same structure type is referred to as a self-referential
structure.
10.2.2  Defining Variables of Structure Types

• Structure definitions do not reserve any space


in memory; rather, each definition creates a
new data type that’s used to define variables.
• Structure variables are defined like variables of
other types.
• The definition
struct card aCard, deck[52], *cardPtr;
declares aCard to be a variable of type struct
card, declares deck to be an array with 52
elements of type struct card and declares
cardPtr to be a pointer to struct card.
10.2  Structure Definitions (Cont.)

• Variables of a given structure type may also be


declared
– by placing a comma-separated list of the variable
names between the closing brace of the structure
definition and the semicolon that ends the structure
definition.
• For example, the preceding definition could
have been incorporated into the struct card
definition as follows:
struct card {
char *face;
char *suit;
} aCard, deck[52], *cardPtr;
10.2.3  Structure Tag Names

• The structure tag name is optional.


• If a structure definition does not contain a
structure tag name, variables of the structure
type may be declared only in the structure
definition—not in a separate declaration.
10.2.4  Operations That Can Be Performed on Structures

• The only valid operations that may be


performed on structures are:
– assigning structure variables to structure variables
of the same type,
– taking the address (&) of a structure variable,
– accessing the members of a structure variable (see
Section 10.4) and
– using the sizeof operator to determine the size of
a structure variable.
10.2.4  Operations That Can Be Performed on Structures (Cont.)

• Structures may not be compared using operators ==


and !=,
– because structure members are not necessarily
stored in consecutive bytes of memory.
• Sometimes there are “holes” in a structure,
– because computers may store specific data types
only on certain memory boundaries such as half-
word, word or double-word boundaries.
• A word is a standard memory unit used to store data in
a computer—usually 2 bytes or 4 bytes.
10.2  Structure Definitions (Cont.)

• Consider the following structure definition, in


which sample1 and sample2 of type struct
example are declared:
struct example {
char c;
int i;
} sample1, sample2;
• A computer with 2-byte words may require that
each member of struct example be aligned
on a word boundary, i.e., at the beginning of a
word (this is machine dependent).
© 2016 Pearson Education, Ltd. All rights reserved.
10.2  Structure Definitions (Cont.)
• Figure 10.1 shows a sample storage alignment for a variable of
type struct example that has been assigned the character
'a' and the integer 97 (the bit representations of the values
are shown).
• If the members are stored beginning at word boundaries,
there’s a 1-byte hole (byte 1 in the figure) in the storage for
variables of type struct example.
• The value in the 1-byte hole is undefined.
• Even if the member values of sample1 and sample2 are in fact
equal, the structures are not necessarily equal, because the
undefined 1-byte holes are not likely to contain identical
values.
10.3  Initializing Structures

• Structures can be initialized using initializer lists


as with arrays.
• To initialize a structure, follow the variable name
in the definition with an equals sign and a brace-
enclosed, comma-separated list of initializers.
• For example, the declaration
struct card aCard = {"Three", "Hearts"};
creates variable aCard to be of type struct card
(as defined in Section 10.2) and initializes
member face to "Three" and member suit to
"Hearts".
10.3  Initializing Structures (Cont.)

• If there are fewer initializers in the list than members


in the structure, the remaining members are
automatically initialized to 0 (or NULL if the member is
a pointer).
• Structure variables defined outside a function
definition (i.e., externally) are initialized to 0 or NULL if
they’re not explicitly initialized in the external
definition.
• Structure variables may also be initialized
– in assignment statements by assigning a structure variable
of the same type,
– or by assigning values to the individual members of the
structure.
10.4  Accessing Structure Members

• Two operators are used to access members of


structures:
– the structure member operator (.)—also called
the dot operator—
– and the structure pointer operator (->)—also
called the arrow operator.
• The structure member operator accesses a structure
member via the structure variable name.
• For example, to print member suit of structure
variable aCard defined in Section 10.3, use the
statement:
printf("%s", aCard.suit); // displays Hearts
10.4  Accessing Structure Members (Cont.)

• The structure pointer operator—consisting of a


minus (-) sign and a greater than (>) sign with no
intervening spaces—
– accesses a structure member via a pointer to the
structure.
• Assume that the pointer cardPtr has been declared
to point to struct card and that the address of
structure aCard has been assigned to cardPtr.
• To print member suit of structure aCard with
pointer cardPtr, use the statement
• printf("%s", cardPtr->suit); // displays Hearts
10.4  Accessing Structure Members (Cont.)
• The expression cardPtr->suit is equivalent to
(*cardPtr).suit, which dereferences the pointer and
accesses the member suit using the structure member
operator.
• The parentheses are needed here because the structure
member operator (.) has a higher precedence than the pointer
dereferencing operator (*).
• The structure pointer operator and structure member operator,
along with parentheses (for calling functions) and brackets ([])
used for array subscripting, have the highest operator
precedence and associate from left to right.
10.4  Accessing Structure Members (Cont.)
• The program of Fig. 10.2 demonstrates the use of the
structure member and structure pointer operators.
• Using the structure member operator, the members of
structure aCard are assigned the values "Ace" and
"Spades", respectively
• Pointer cardPtr is assigned the address of structure aCard
• Function printf prints the members of structure variable
aCard using;
– the structure member operator with variable name aCard,
– the structure pointer operator with pointer cardPtr
– and the structure member operator with dereferenced
pointer cardPtr
© 2016 Pearson Education, Ltd. All rights reserved.
© 2016 Pearson Education, Ltd. All rights reserved.
10.5  Using Structures with Functions

• Structures may be passed to functions


– by passing individual structure members,
– by passing an entire structure
– or by passing a pointer to a structure.
• When structures or individual structure members
are passed to a function, they’re passed by value.
• Therefore, the members of a caller’s structure
cannot be modified by the called function.
• To pass a structure by reference, pass the address
of the structure variable.
10.5  Using Structures with Functions (Cont.)

• Arrays of structures—like all other arrays—are


automatically passed by reference.
• To pass an array by value, create a structure
with the array as a member.
• Structures are passed by value, so the array is
passed by value.
10.6  typedef

• The keyword typedef provides a mechanism


for creating synonyms (or aliases) for
previously defined data types.
• Names for structure types are often defined
with typedef to create shorter type names.
• For example, the statement
typedef struct card Card;
defines the new type name Card as a synonym
for type struct card.
• C programmers often use typedef to define a
structure type, so a structure tag is not required.
© 2016 Pearson Education, Ltd. All rights reserved.
10.6  typedef (Cont.)
• For example, the following definition
typedef struct {
char *face;
char *suit;
} Card;
creates the structure type Card without the
need for a separate typedef statement.

© 2016 Pearson Education, Ltd. All rights reserved.


10.6  typedef (Cont.)

• Card can now be used to declare variables of


type struct card.
• The declaration
Card deck[52];
declares an array of 52 Card structures (i.e.,
variables of type struct card).
• Creating a new name with typedef does not
create a new type; typedef simply creates a
new type name, which may be used as an alias
for an existing type name.
10.6  typedef (Cont.)
• A meaningful name helps make the program self-
documenting.
• For example, when we read the previous declaration, we
know “deck is an array of 52 Cards.”
• Often, typedef is used to create synonyms for the basic data
types.
• For example, a program requiring four-byte integers may use
type int on one system and type long on another.
• Programs designed for portability often use typedef to
create an alias for four-byte integers, such as Integer.
• The alias Integer can be changed once in the program to
make the program work on both systems.
10.7  Example: High-Performance Card Shuffling and Dealing
Simulation

• The program in Fig. 10.3 is based on the card


shuffling and dealing simulation discussed in
Chapter 7.
• The program represents the deck of cards as an
array of structures and uses high-performance
shuffling and dealing algorithms.
• The program output is shown in Fig. 10.4.
© 2016 Pearson Education, Ltd. All rights reserved.
© 2016 Pearson Education, Ltd. All rights reserved.
© 2016 Pearson Education, Ltd. All rights reserved.
© 2016 Pearson Education, Ltd. All rights reserved.
© 2016 Pearson Education, Ltd. All rights reserved.
10.7  Example: High-Performance Card Shuffling and Dealing Simulation (Cont.)

• In the program, function fillDeck initializes the


Card array in order with “Ace” through “King” of
each suit.
• The Card array is passed to function shuffle,
where the high-performance shuffling algorithm is
implemented.
• Function shuffle takes an array of 52 Cards as an
argument.
• The function loops through the 52 Cards
10.7  Example: High-Performance Card Shuffling and Dealing Simulation (Cont.)

• For each card, a number between 0 and 51 is picked


randomly.
• Next, the current Card and the randomly selected Card are
swapped in the array
• A total of 52 swaps are made in a single pass of the entire
array, and the array of Cards is shuffled!
• This algorithm cannot suffer from indefinite postponement like
the shuffling algorithm presented in Chapter 7.
• Because the Cards were swapped in place in the array, the
high-performance dealing algorithm implemented in function
deal requires only one pass of the array to deal the shuffled
Cards .
10.8  Unions

• A union is a derived data type—like a structure


—with members that share the same storage
space.
• For different situations in a program,
– some variables may not be relevant,
– but other variables are
– so a union shares the space instead of wasting
storage on variables that are not being used.
• The members of a union can be of any data type.

© 2016 Pearson Education, Ltd. All rights reserved.


10.8  Unions (Cont.)
• The number of bytes used to store a union must
be at least enough to hold the largest member.
• In most cases, unions contain two or more data
types.
• Only one member, and thus one data type, can be
referenced at a time.
• It’s your responsibility to ensure that the data in a
union is referenced with the proper data type.
10.8.1  Union Declarations

• A union definition has the same format as a structure


definition.
• The union definition
union number {
int x;
double y;
};
indicates that number is a union type with members
int x and double y.
• The union definition is normally placed in a header and
included in all source files that use the union type.
10.8.2  Operations That Can Be Performed on Unions

• The operations that can be performed on a


union are:
– assigning a union to another union of the same type,
– taking the address (&) of a union variable,
– and accessing union members using the structure
member operator and the structure pointer
operator.
• Unions may not be compared using operators ==
and != for the same reasons that structures
cannot be compared.

© 2016 Pearson Education, Ltd. All rights reserved.


10.8.3  Initializing Unions in Declarations
• In a declaration, a union may be initialized with a value
of the same type as the first union member.
• For example, with the union in Section 10.8.1, the
statement
union number value = {10};
is a valid initialization of union variable value because
the union is initialized with an int,
• but the following declaration would truncate the
floating-point part of the initializer value and normally
would produce a warning from the compiler:
union number value = {1.43};
10.8.4  Demonstrating Unions

• The program in Fig. 10.5 uses the variable value


of type union number to display the value stored
in the union as both an int and a double.
• The program output is implementation
dependent.
• The program output shows that the internal
representation of a double value can be quite
different from the representation of int.
© 2016 Pearson Education, Ltd. All rights reserved.
© 2016 Pearson Education, Ltd. All rights reserved.
10.9  Bitwise Operators
• Computers represent all data internally as sequences
of bits.
• Each bit can assume the value 0 or the value 1.
• On most systems, a sequence of 8 bits forms a byte
– the typical storage unit for a variable of type char.
• Other data types are stored in larger numbers of
bytes.
• The bitwise operators are used to manipulate the
bits of integral operands both signed and unsigned.
• Unsigned integers are normally used with the
bitwise operators.
10.9  Bitwise Operators (Cont.)
• The bitwise operator discussions in this section show
the binary representations of the integer operands.
• For a detailed explanation of the binary (also called
base-2) number system see Appendix C.
• The bitwise operators are
– bitwise AND (&),
– bitwise inclusive OR (|),
– bitwise exclusive OR (^); (also known as bitwise
XOR),
– left shift (<<),
– right shift (>>)
– complement (~).
© 2016 Pearson Education, Ltd. All rights reserved.
10.9  Bitwise Operators (Cont.)

• The bitwise AND, bitwise inclusive OR and bitwise


exclusive OR operators compare their two operands
bit by bit.
• The bitwise AND operator sets each bit in the result to
– 1 if the corresponding bit in both operands is 1.
• The bitwise inclusive OR operator sets each bit in the
result to
– 1 if the corresponding bit in either (or both)
operand(s) is 1.
• The bitwise exclusive OR operator sets each bit in the
result to
– 1 if the corresponding bit in exactly one operand is 1.
10.9  Bitwise Operators (Cont.)
• The left-shift operator shifts the bits of its left operand
to the left by the number of bits specified in its right
operand.
• The right-shift operator shifts the bits in its left
operand to the right by the number of bits specified in
its right operand.
• The bitwise complement operator sets all 0 bits in its
operand to 1 in the result and sets all 1 bits to 0 in the
result.
• Detailed discussions of each bitwise operator appear
in the examples that follow.
• The bitwise operators are summarized in Fig. 10.6.
© 2016 Pearson Education, Ltd. All rights reserved.
10.9.1  Displaying an Unsigned Integer in Bits

• When using the bitwise operators, it’s useful to


display values in binary to show the precise
effects of these operators.
• The program of Fig. 10.7 prints an unsigned
int in its binary representation in groups of
eight bits each for readability.
• For the examples in this section, we assume an
implementation where unsigned ints are
stored in 4 bytes (32 bits) of memory.

© 2016 Pearson Education, Ltd. All rights reserved.


© 2016 Pearson Education, Ltd. All rights reserved.
© 2016 Pearson Education, Ltd. All rights reserved.
10.9.1  Displaying an Unsigned Integer in Bits (Cont.)

• Function displayBits uses the bitwise AND operator


to combine variable value with variable
displayMask
• Often, the bitwise AND operator is used with an
operand called a mask
– an integer value with specific bits set to 1.
• Masks are used to hide some bits in a value while
selecting other bits.
• In function displayBits, mask variable
displayMask is assigned the value
1 << 31 (10000000 00000000 00000000 00000000)
10.9.1  Displaying an Unsigned Integer in Bits (Cont.)

• The left-shift operator shifts the value 1 from


the low-order (rightmost) bit to the high-order
(leftmost) bit in displayMask and fills in 0 bits
from the right.
• putchar(value & displayMask ? '1' : '0');
determines whether a 1 or a 0 should be printed
for the current leftmost bit of variable value.
• When value and displayMask are combined
using &,
– all the bits except the high-order bit in variable
value are “masked off” (hidden), because any
bit “ANDed” with 0 yields 0.
10.9.1  Displaying an Unsigned Integer in Bits (Cont.)
• putchar(value & displayMask ? '1' : '0');
• If the leftmost bit is 1, value & displayMask
evaluates to a nonzero (true) value and 1 is
printed—otherwise, 0 is printed.
• Variable value is then left shifted one bit by
the expression value <<= 1 (this is equivalent
to value = value << 1).
• These steps are repeated for each bit in
unsigned variable value.
10.9.1  Displaying an Unsigned Integer in Bits (Cont.)
• Figure 10.8 summarizes the results of combining two
bits with the bitwise AND operator.
10.9.2  Making Function displayBits More Scalable and Portable

• In Fig. 10.7, we hard coded the integer 31 to


indicate that the value 1 should be shifted to the
leftmost bit in the variable displayMask.
• Similarly, we hard coded the integer 32 to
indicate that the loop should iterate 32 times—
once for each bit in variable value.
• We assumed that unsigned ints are always
stored in 32 bits (4 bytes) of memory.
• Many of today’s popular computers use 32-bit
or 64-bit word hardware architectures.
10.9.2  Making Function displayBits More Scalable and
Portable (Cont.)

• As a C programmer, you’ll tend to work across many


hardware architectures, and sometimes unsigned
ints will be stored in smaller or larger numbers of
bits.
• We can make the program in Fig. 10.7 more scalable
and more portable by replacing the integer 31 with
the expression
CHAR_BIT * sizeof(unsigned int) - 1
and by replacing the integer 32 with the expression
CHAR_BIT * sizeof(unsigned int)
10.9.2  Making Function displayBits More Scalable and Portable (Cont.)

• The symbolic constant CHAR_BIT (defined in


<limits.h>) represents the number of bits in a
byte (normally 8).
• On a computer that uses 32-bit words, the
expression sizeof(unsigned int) evaluates to
4, so the two preceding expressions evaluate to
31 and 32, respectively.
• On a computer that uses 16-bit words, the
sizeof expression evaluates to 2 and the two
preceding expressions evaluate to 15 and 16,
respectively.
10.9.3  Using the Bitwise AND, Inclusive OR, Exclusive OR and
Complement Operators

• Figure 10.9 demonstrates the use of the bitwise


AND operator, the bitwise inclusive OR operator,
the bitwise exclusive OR operator and the
bitwise complement operator.
• The program uses function displayBits to
print the unsigned int values.
• The output is shown in Fig. 10.10.
© 2016 Pearson Education, Ltd. All rights reserved.
© 2016 Pearson Education, Ltd. All rights reserved.
© 2016 Pearson Education, Ltd. All rights reserved.
© 2016 Pearson Education, Ltd. All rights reserved.
© 2016 Pearson Education, Ltd. All rights reserved.
10.9.3  Using the Bitwise AND, Inclusive OR, Exclusive OR
and Complement Operators (Cont.)
• In Fig. 10.9, integer variable number1 is assigned
the value 65535 (00000000 00000000 11111111
11111111) and variable mask is assigned the value
1 (00000000 00000000 00000000 00000001).
• When number1 and mask are combined using the
bitwise AND operator (&) in the expression
number1 & mask, the result is 00000000 00000000
00000000 00000001.
• All the bits except the low-order bit in variable
number1 are “masked off” (hidden) by “ANDing”
with variable mask.
• The bitwise inclusive OR operator is used to set
specific bits to 1 in an operand.
© 2016 Pearson Education, Ltd. All rights reserved.
10.9.3  Using the Bitwise AND, Inclusive OR, Exclusive OR
and Complement Operators (Cont.)
• In Fig. 10.9, variable number1 is assigned 15 (00000000
00000000 00000000 00001111), and variable setBits is
assigned 241 (00000000 00000000 00000000 11110001)
• When number1 and setBits are combined using the
bitwise inclusive OR operator in the expression number1 |
setBits, the result is 255 (00000000 00000000
00000000 11111111).
• Figure 10.11 summarizes the results of combining two bits
with the bitwise inclusive OR operator.
10.9.3  Using the Bitwise AND, Inclusive OR, Exclusive OR and Complement Operators
(Cont.)

• The bitwise exclusive OR operator (^) sets each bit in the result
to 1 if exactly one of the corresponding bits in its two
operands is 1.
• In Fig. 10.9, variables number1 and number2 are assigned the
values 139 (00000000 00000000 00000000 10001011) and
199 (00000000 00000000 00000000 11000111)
• When these variables are combined with the bitwise exclusive
OR operator in the expression number1 ^ number2, the result
is 00000000 00000000 00000000 01001100.
• Figure 10.12 summarizes the results of combining two bits
with the bitwise exclusive OR operator.
10.9.3  Using the Bitwise AND, Inclusive OR, Exclusive OR and
Complement Operators (Cont.)

• The bitwise complement operator (~) sets all 1


bits in its operand to 0 in the result and sets all 0
bits to 1 in the result—otherwise referred to as
“taking the one’s complement of the value.”
• In Fig. 10.9, variable number1 is assigned the
value 21845 (00000000 00000000 01010101
01010101)
• When the expression ~number1 is evaluated, the
result is 11111111 11111111 10101010
10101010.
© 2016 Pearson Education, Ltd. All rights reserved.
10.9.4  Using the Bitwise Left- and Right-Shift Operators
• The program of Fig. 10.13 demonstrates the
left-shift operator (<<) and the right-shift
operator (>>).
• Function displayBits is used to print the
unsigned int values.
© 2016 Pearson Education, Ltd. All rights reserved.
© 2016 Pearson Education, Ltd. All rights reserved.
© 2016 Pearson Education, Ltd. All rights reserved.
10.9.4  Using the Bitwise Left- and Right-Shift Operators
(Cont.)
• The left-shift operator (<<) shifts the bits of its
left operand to the left by the number of bits
specified in its right operand.
• Bits vacated to the right are replaced with 0s; 1s
shifted off the left are lost.
• In Fig. 10.13, variable number1 is assigned the
value 960 (00000000 00000000 00000011
11000000)
• The result of left shifting variable number1 8
bits in the expression number1 << 8 is 49152
(00000000 00000011 11000000 00000000).
10.9.4  Using the Bitwise Left- and Right-Shift Operators (Cont.)
• The right-shift operator (>>) shifts the bits of its
left operand to the right by the number of bits
specified in its right operand.
• Performing a right shift on an unsigned int
causes the vacated bits at the left to be replaced
by 0s; 1s shifted off the right are lost.
• In Fig. 10.13, the result of right shifting number1
in the expression number1 >> 8 is 3 (00000000
00000000 00000000 00000011).
10.9.5  Bitwise Assignment Operators
• Each binary bitwise operator has a corresponding
assignment operator.
• These bitwise assignment operators are shown
in Fig. 10.14 and are used in a manner similar to
the arithmetic assignment operators introduced in
Chapter 3.
10.9  Bitwise Operators (Cont.)
• Figure 10.15 shows the precedence and associativity of the
various operators introduced to this point in the text.
They’re shown top to bottom in decreasing order of
precedence.
10.10  Bit Fields

• C enables you to specify the number of bits in


which an unsigned int or int member of a
structure or union is stored.
• This is referred to as a bit field.
• Bit fields enable better memory utilization by
storing data in the minimum number of bits
required.
• Bit field members must be declared as int or
unsigned int.

© 2016 Pearson Education, Ltd. All rights reserved.


10.10  Bit Fields (Cont.)

• Consider the following structure definition:


struct bitCard {
unsigned int face : 4;
unsigned int suit : 2;
unsigned int color : 1;
};
which contains three unsigned int bit fields;
– face, suit and color
– used to represent a card from a deck of 52
cards.
© 2016 Pearson Education, Ltd. All rights reserved.
10.10  Bit Fields (Cont.)
• A bit field is declared by following an unsigned int
or int member name with a colon (:) and an integer
constant representing the width of the field (i.e., the
number of bits in which the member is stored).
• The constant representing the width must be an
integer between 0 and the total number of bits used to
store an int on your system, inclusive.
• Our examples were tested on a computer with 4-byte
(32-bit) integers.
• The preceding structure definition indicates that
member face is stored in 4 bits, member suit is
stored in 2 bits and member color is stored in 1 bit.

© 2016 Pearson Education, Ltd. All rights reserved.


10.10  Bit Fields (Cont.)
• The number of bits is based on the desired range
of values for each structure member.
• Member face stores values from 0 (Ace) through
12 (King)—4 bits can store values in the range 0–
15.
• Member suit stores values from 0 through 3 (0 =
Diamonds, 1 = Hearts, 2 = Clubs, 3 = Spades)—2
bits can store values in the range 0–3.
• Finally, member color stores either 0 (Red) or 1
(Black)—1 bit can store either 0 or 1.
• Figure 10.16 (output shown in Fig. 10.17) creates
array deck containing 52 struct bitCard
structures
10.10  Bit Fields (Cont.)
• Function fillDeck inserts the 52 cards in the
deck array and function deal prints the 52 cards.
• Notice that bit field members of structures are
accessed exactly as any other structure member.
• Member color is included as a means of
indicating the card color on a system that allows
color displays.
• It’s possible to specify an unnamed bit field to be
used as padding in the structure.

© 2016 Pearson Education, Ltd. All rights reserved.


10.10  Bit Fields (Cont.)

• For example, the structure definition


struct example {
unsigned int a : 13;
unsignedint : 19;
unsigned int b : 4;
};
uses an unnamed 19-bit field as padding—
nothing can be stored in those 19 bits.
• Member b (on our 4-byte-word computer) is
stored in another storage unit.
© 2016 Pearson Education, Ltd. All rights reserved.
© 2016 Pearson Education, Ltd. All rights reserved.
© 2016 Pearson Education, Ltd. All rights reserved.
© 2016 Pearson Education, Ltd. All rights reserved.
10.10  Bit Fields (Cont.)
• An unnamed bit field with a zero width is used to align the next
bit field on a new storage-unit boundary.
• For example, the structure definition
struct example {
unsigned int a : 13;
unsigned int : 0;
unsigned int b : 4;
};
uses an unnamed 0-bit field to skip the remaining bits (as many
as there are) of the storage unit in which a is stored and to align b
on the next storage-unit boundary.
10.11  Enumeration Constants

• An enumeration (discussed briefly in Section 5.11),


introduced by the keyword enum, is a set of integer
enumeration constants represented by
identifiers.
• Values in an enum start with 0, unless specified
otherwise, and are incremented by 1.
• For example, the enumeration
enum months {
JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP,
OCT, NOV, DEC};
creates a new type, enum months, in which the
identifiers are set to the integers 0 to 11,
respectively.
10.11  Enumeration Constants (Cont.)

• To number the months 1 to 12, use the following


enumeration:
enum months {
JAN = 1, FEB, MAR, APR, MAY, JUN, JUL, AUG,
SEP, OCT, NOV, DEC};
• Because the first value in the preceding
enumeration is explicitly set to 1, the remaining
values are incremented from 1, resulting in the
values 1 through 12.
• The identifiers in an enumeration must be unique.
• The value of each enumeration constant of an
enumeration can be set explicitly in the definition
by assigning a value to the identifier.
10.11  Enumeration Constants (Cont.)
• Multiple members of an enumeration can have the
same constant value.
• In the program of Fig. 10.18, the enumeration
variable month is used in a for statement to print
the months of the year from the array monthName.
• We’ve made monthName[0] the empty string "".
• You could set monthName[0] to a value such as
***ERROR*** to indicate that a logic error
occurred.
© 2016 Pearson Education, Ltd. All rights reserved.
© 2016 Pearson Education, Ltd. All rights reserved.
10.12  Anonymous Structures and Unions
• C11 supports anonymous structs and unions that can be
nested in named structs and unions
• Members in a nested anonymous struct and union are
considered to be members of the enclosing type and can be
accessed directly through an object of the enclosing type

• Example For a variable myStruct of


struct MyStruct { type struct MyStruct, you
int member1; can access the members as:
int member2; myStruct.member1
myStruct.member2
struct { myStruct.nestedMember1
int nestedMember1; myStruct.nestedMember2
int nestedMember2;
};
};

You might also like