C55. C Type Qualifiers


Type Qualifiers
There are two type qualifiers: const and volatile. (C99 has a third type qual­ifier, restrict, which is used only with pointers.) Since the use of volatile is limited to low-level programming, I'll postpone discussing it until Section 20.3. const is used to declare objects that resemble variables but are "read-only": a program may access the value of a const object, but can't change it.
For exam­ple, the declaration
const int n = 10;
creates a const object named n whose value is 10. The declaration
const int tax_brackets[] = {750, 2250, 3750, 5250, 7000};
creates a const array named tax_brackets.
Declaring an object to be const has several advantages:
It's a form of documentation: it alerts anyone reading the program to the read­only nature of the object.
The compiler can check that the program doesn't inadvertently attempt to change the value of the object.
When programs are written for certain types of applications (embedded sys­tems, in particular), the compiler can use the word const to identify data to be stored in ROM (read-only memory).
At first glance, it might appear that const serves the same role as the #def ine directive, which we've used in previous chapters to create names for constants. There are significant differences between #def ine and const, how­ever:
We can use #def ine to create a name for a numerical, character, or string constant, const can be used to create read-only objects of any type, including arrays, pointers, structures, and unions.
const objects are subject to the same scope rules as variables; constants cre­ated using #def ine aren't. In particular, we can't use #define to create a constant with block scope.
The value of a const object, unlike the value of a macro, can be viewed in a debugger.

Declarators
A declarator consists of an identifier (the name of the variable or function being declared), possibly preceded by the * symbol or followed by [] or (). By com­bining *. []. and (), we can create declarators of mind-numbing complexity.
Before we look at the more complicated declarators, let's review the declara­tors that we've seen in previous chapters. In the simplest case, a declarator is just an identifier, like i in the following example:
int i;
Declarators may also contain the symbols *, [ ], and ():
A declarator that begins with * represents a pointer: int *p;
A declarator that ends with [] represents an array: int a [10];
The brackets may be left empty if the array is a parameter, if it has an initial­izer, or if its storage class is extern:
extern int a[];

Using Type Definitions to Simplify Declarations
Some programmers use type definitions to help simplify complex declarations. Consider the declaration of x that we examined earlier in this section:
int *(*x[10]) (void);
To make x's type easier to understand, we could use the following series of type definitions:
typedef int *Fcn(void);
typedef Fcn *Fcn_ptr;
 typedef Fcn_ptr Fcn_ptr_array[10];
 Fcn_ptr_array x;
If we read these lines in reverse order, we see that x has type Fcn_ptr_array, a Fcn_ptr_array is an array of Fcn_ptr values, a Fcn_ptr is a pointer to type Fcn, and a Fcn is a function that has no arguments and returns a pointer to an int value.

No comments: