Monday, October 4, 2010

C,C++ Tutorial : Unions

generally of different types, at different times. Declaring a union is similar to
declaring a structure. Its general form is

union union-type-name {
type member-name;
type member-name;
type member-name;
} union-variables;

For example:

union u_type {
int i;
char ch;
};

This declaration does not create any variables. You may declare a variable either
by placing its name at the end of the declaration or by using a separate declaration
statement. In C, to declare a union variable called cnvt of type u_type using the
definition just given, write
union u_type cnvt;
When declaring union variables in C++, you need use only the type name—
you don't need to precede it with the keyword union. For example, this is how
cnvt is declared in C++:
u_type cnvt;
In C++, preceding this declaration with the keyword union is allowed, but redundant.
In C++, the name of a union defines a complete type name. In C, a union name is its
tag and it must be preceded by the keyword union. (This is similar to the situation
with structures described earlier.) However, since the programs in this chapter are
valid for both C and C++, the C-style declaration form will be used.
In cnvt, both integer i and character ch share the same memory location. Of
course, i occupies 2 bytes (assuming 2-byte integers) and ch uses only 1. Figure 7-2
shows how i and ch share the same address. At any point in your program, you can
refer to the data stored in a cnvt as either an integer or a character.
When a union variable is declared, the compiler automatically allocates enough
storage to hold the largest member of the union. For example (assuming 2-byte
integers), cnvt is 2 bytes long so that it can hold i, even though ch requires only
1 byte.

To access a member of a union, use the same syntax that you would use for
structures: the dot and arrow operators. If you are operating on the union directly,
use the dot operator. If the union is accessed through a pointer, use the arrow
operator. For example, to assign the integer 10 to element i of cnvt, write
cnvt.i = 10;
In the next example, a pointer to cnvt is passed to a function:
void func1(union u_type *un)
{
un->i = 10; /* assign 10 to cnvt using
function */
}
Using a union can aid in the production of machine-independent (portable)
code. Because the compiler keeps track of the actual sizes of the union members,
no unnecessary machine dependencies are produced. That is, you need not worry
about the size of an int, long, float, or whatever.
Unions are used frequently when specialized type conversions are needed
because you can refer to the data held in the union in fundamentally different
ways. For example, you may use a union to manipulate the bytes that comprise a
double in order to alter its precision or to perform some unusual type of rounding.To get an idea of the usefulness of a union when nonstandard type conversions
are needed, consider the problem of writing a short integer to a disk file. The C/C++
standard library defines no function specifically designed to write a short integer to
a file. While you can write any type of data to a file using fwrite(), using fwrite()
incurs excessive overhead for such a simple operation. However, using a union you
can easily create a function called putw() , which writes the binary representation of
a short integer to a file one byte at a time. (This example assumes that short integers
are 2 bytes long.) To see how, first create a union consisting of one short integer and
a 2-byte character array:
union pw {
short int i;
char ch[2];
};
Now, you can use pw to create the version of putw() shown in the following program.
#include <stdio.h>
union pw {
short int i;
char ch[2];
};
int putw(short int num, FILE *fp);
int main(void)
{
FILE *fp;
fp = fopen("test.tmp", "wb+");
putw(1000, fp); /* write the value 1000 as an integer */
fclose(fp);
return 0;
}
int putw(short int num, FILE *fp)
{
union pw word;word.i = num;
putc(word.ch[0], fp); /* write first half */
return putc(word.ch[1], fp); /* write second half */
}
Although putw() is called with a short integer, it can still use the standard function
putc() to write each byte in the integer to a disk file one byte at a time.
 

**Note :C++ supports a special type of union called an anonymous union which is
discussed in Part Two of this book.

Bit-Fields in C, C++

Unlike some other computer languages, C/C++ has a built-in feature called a bit-field
that allows you to access a single bit. Bit-fields can be useful for a number of reasons,
such as:
If storage is limited, you can store several Boolean (true/false) variables in
one byte.
Certain devices transmit status information encoded into one or more bits
within a byte.
Certain encryption routines need to access the bits within a byte.
Although these tasks can be performed using the bitwise operators, a bit-field can
add more structure (and possibly efficiency) to your code.
To access individual bits, C/C++ uses a method based on the structure. In fact,
a bit-field is really just a special type of structure member that defines how long,
in bits, the field is to be. The general form of a bit-field definition is
struct struct-type-name {
type name1 : length;
type name2 : length;
..
.
type nameN : length;
} variable_list;
Here, type is the type of the bit-field and length is the number of bits in the field.
A bit-field must be declared as an integral or enumeration type. Bit-fields of length
1 should be declared as unsigned, because a single bit cannot have a sign.
Bit-fields are frequently used when analyzing input from a hardware device.
For example, the status port of a serial communications adapter might return a
status byte organized like this:

Bit    Meaning When Set

0        Change in clear-to-send line
1         Change in data-set-ready
2         Trailing edge detected
3        Change in receive line
4       Clear-to-send
5        Data-set-ready
6      Telephone ringing
7       Received signal

You can represent the information in a status byte using the following bit-field:

struct status_type {
unsigned delta_cts: 1;
unsigned delta_dsr: 1;
unsigned tr_edge: 1;
unsigned delta_rec: 1;
unsigned cts: 1;
unsigned dsr: 1;
unsigned ring: 1;
unsigned rec_line: 1;
} status;

You might use a routine similar to that shown here to enable a program to determine
when it can send or receive data.
status = get_port_status();
if(status.cts) printf("clear to send");
if(status.dsr) printf("data ready");
To assign a value to a bit-field, simply use the form you would use for any other type
of structure element. For example, this code fragment clears the ring field:
status.ring = 0;
As you can see from this example, each bit-field is accessed with the dot operator.
However, if the structure is referenced through a pointer, you must use the −> operator.
You do not have to name each bit-field. This makes it easy to reach the bit you
want, bypassing unused ones. For example, if you only care about the cts and dsr
bits, you could declare the status_type structure like this:
struct status_type {
unsigned : 4;
unsigned cts: 1;
unsigned dsr: 1;
} status;
Also, notice that the bits after dsr do not need to be specified if they are not used.
It is valid to mix normal structure members with bit-fields. For example,
struct emp {
struct addr address;
float pay;
unsigned lay_off: 1; /* lay off or active */
unsigned hourly: 1; /* hourly pay or wage */
unsigned deductions: 3; /* IRS deductions */
};
defines an employee record that uses only 1 byte to hold three pieces of information:
the employee's status, whether the employee is salaried, and the number of deductions.
Without the bit-field, this information would have taken 3 bytes.
Bit-fields have certain restrictions. You cannot take the address of a bit-field. Bitfields
cannot be arrayed. They cannot be declared as static. You cannot know, from
machine to machine, whether the fields will run from right to left or from left to right;
this implies that any code using bit-fields may have some machine dependencies.
Other restrictions may be imposed by various specific implementations, so check the
user manual for your compiler.

Arrays and Structures Within Structures

A member of a structure may be either a simple or compound type. A simple
member is one that is of any of the built-in data types, such as integer or character.
You have already seen one type of compound element: the character arrays used in
addr. Other compound data types include one-dimensional and multidimensional
arrays of the other data types and structures.
A member of a structure that is an array is treated as you might expect from
the earlier examples. For example, consider this structure:
struct x {
int a[10][10]; /* 10 x 10 array of ints */
float b;
} y;
To reference integer 3,7 in a of structure y, write
y.a[3][7]
When a structure is a member of another structure, it is called a nested structure.
For example, the structure address is nested inside emp in this example:
struct emp {
struct addr address; /* nested structure */
float wage;
} worker;
Here, structure emp has been defined as having two members. The first is a structure
of type addr, which contains an employee's address. The other is wage, which holds
the employee's wage. The following code fragment assigns 93456 to the zip element
of address.

worker.address.zip = 93456;
As you can see, the members of each structure are referenced from outermost to
innermost. Standard C specifies that structures may be nested to at least 15 levels.
Standard C++ suggests that at least 256 levels of nesting be allowed.

Friday, October 1, 2010

Using Structure Pointers in C,C++

There are two primary uses for structure pointers: to pass a structure to a function
using call by reference, and to create linked lists and other dynamic data structures that
rely on dynamic allocation. This chapter covers the first use.
There is one major drawback to passing all but the simplest structures to functions:
the overhead needed to push the structure onto the stack when the function call is
executed. (Recall that arguments are passed to functions on the stack.) For simple
structures with few members, this overhead is not too great. If the structure contains
many members, however, or if some of its members are arrays, run-time performance
may degrade to unacceptable levels. The solution to this problem is to pass only a
pointer to the function.
When a pointer to a structure is passed to a function, only the address of the
structure is pushed on the stack. This makes for very fast function calls. A second
advantage, in some cases, is when a function needs to reference the actual structure
used as the argument, instead of a copy. By passing a pointer, the function can
modify the contents of the structure used in the call.
To find the address of a structure variable, place the & operator before the
structure's name. For example, given the following fragment:
struct bal {
float balance;
char name[80];
} person;
struct bal *p; /* declare a structure pointer */
then
p = &person;

places the address of the structure person into the pointer p.
To access the members of a structure using a pointer to that structure, you must
use the −> operator. For example, this references the balance field:
p->balance
The −> is usually called the arrow operator, and consists of the minus sign followed
by a greater-than sign. The arrow is used in place of the dot operator when you are
accessing a structure member through a pointer to the structure.
To see how a structure pointer can be used, examine this simple program, which
prints the hours, minutes, and seconds on your screen using a software timer.
/* Display a software timer. */
#include <stdio.h>
#define DELAY 128000
struct my_time {
int hours;
int minutes;
int seconds;
} ;
void display(struct my_time *t);
void update(struct my_time *t);
void delay(void);
int main(void)
{
struct my_time systime;
systime.hours = 0;
systime.minutes = 0;
systime.seconds = 0;
for(;;) {
update(&systime);
display(&systime);
}
return 0;
}

void update(struct my_time *t)
{
t->seconds++;
if(t->seconds==60) {
t->seconds = 0;
t->minutes++;
}
if(t->minutes==60) {
t->minutes = 0;
t->hours++;
}
if(t->hours==24) t->hours = 0;
delay();
}
void display(struct my_time *t)
{
printf("%02d:", t->hours);
printf("%02d:", t->minutes);
printf("%02d\n", t->seconds);
}
void delay(void)
{
long int t;
/* change this as needed */
for(t=1; t<DELAY; ++t) ;
}
The timing of this program is adjusted by changing the definition of DELAY.
As you can see, a global structure called my_time is defined but no variable is
declared. Inside main() , the structure systime is declared and initialized to 00:00:00.
This means that systime is known directly only to the main() function.
The functions update() (which changes the time) and display() (which prints
the time) are passed the address of systime. In both functions, their arguments are
declared as a pointer to a my_time structure.
Inside update() and display() , each member of systime is accessed via a pointer.
Because update() receives a pointer to the systime structure, it can update its value.

For example, to set the hours back to 0 when 24:00:00 is reached, update() contains
this line of code:
if(t->hours==24) t->hours = 0;
This tells the compiler to take the address of t (which points to systime in main() )
and to reset hours to zero.
Remember, use the dot operator to access structure elements when operating on
the structure itself. When you have a pointer to a structure, use the arrow operator.

Structure Pointers in C, C++

C/C++ allows pointers to structures just as it allows pointers to any other type
of variable. However, there are some special aspects to structure pointers that
you should know.


Declaring a Structure Pointer
 
Like other pointers, structure pointers are declared by placing * in front of a structure
variable's name. For example, assuming the previously defined structure addr, the
following declares addr_pointer as a pointer to data of that type:
struct addr *addr_pointer;
Remember, in C++ it is not necessary to precede this declaration with the keyword
struct.

Passing Entire Structures to Functions in C,C++

When a structure is used as an argument to a function, the entire structure is passed
using the standard call-by-value method. Of course, this means that any changes 

made to the contents of the structure inside the function to which it is passed do not
affect the structure used as an argument.
When using a structure as a parameter, remember that the type of the argument
must match the type of the parameter. For example, in the following program both the
argument arg and the parameter parm are declared as the same type of structure.
#include <stdio.h>
/* Define a structure type. */
struct struct_type {
int a, b;
char ch;
} ;
void f1(struct struct_type parm);
int main(void)
{
struct struct_type arg;
arg.a = 1000;
f1(arg);
return 0;
}
void f1(struct struct_type parm)
{
printf("%d", parm.a);
}
As this program illustrates, if you will be declaring parameters that are structures,
you must make the declaration of the structure type global so that all parts of your
program can use it. For example, had struct_type been declared inside main() (for
example), then it would not have been visible to f1().
As just stated, when passing structures, the type of the argument must match
the type of the parameter. It is not sufficient for them to simply be physically similar;
their type names must match. For example, the following version of the preceding
program is incorrect and will not compile because the type name of the argument
used to call f1() differs from the type name of its parameter.

/* This program is incorrect and will not compile. */
#include <stdio.h>
/* Define a structure type. */
struct struct_type {
int a, b;
char ch;
} ;
/* Define a structure similar to struct_type,
but with a different name. */
struct struct_type2 {
int a, b;
char ch;
} ;
void f1(struct struct_type2 parm);
int main(void)
{
struct struct_type arg;
arg.a = 1000;
f1(arg); /* type mismatch */
return 0;
}
void f1(struct struct_type2 parm)
{
printf("%d", parm.a);

Passing Structure Members to Functions in C,C++

When you pass a member of a structure to a function, you are actually passing
the value of that member to the function. Therefore, you are passing a simple
variable (unless, of course, that element is compound, such as an array). For
example, consider this structure:
struct fred
{
char x;
int y;
float z;
char s[10];
} mike;
Here are examples of each member being passed to a function:
func(mike.x); /* passes character value of x */
func2(mike.y); /* passes integer value of y */
func3(mike.z); /* passes float value of z */
func4(mike.s); /* passes address of string s */
func(mike.s[2]); /* passes character value of s[2] */
If you wish to pass the address of an individual structure member, put the & operator
before the structure name. For example, to pass the address of the members of the
structure mike, write
func(&mike.x); /* passes address of character x */
func2(&mike.y); /* passes address of integer y */
func3(&mike.z); /* passes address of float z */
func4(mike.s); /* passes address of string s */
func(&mike.s[2]); /* passes address of character s[2] */
Remember that the & operator precedes the structure name, not the individual
member name. Note also that s already signifies an address, so no & is required.