Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Advanced C 1992

.pdf
Скачиваний:
96
Добавлен:
17.08.2013
Размер:
4.28 Mб
Скачать

Part III • Working with Others

496

CAll AboutCHeader FilesCC C C

C13C C

C13C CC C C

C C C

All About Header Files

Header files are a feature of the C language that helps the programmer write better programs. There are two types of header files: the files that the programmer writes and the files that come with your compiler. This chapter covers fifteen standard C header files. First, though, the chapter reviews the usage of function prototypes and how to make your prototypes more effective.

The terms header file and include file are commonly used interchangeably. There are no differences between the two—header files are include files.

Function Prototypes

One of the most valuable improvements to C is the addition of function prototypes. A function prototype specifies the order and types of arguments that will be passed to

497

Part III • Working with Others

a function. It specifies also the type of the function’s return value, if the function returns a value. In early versions of C, the compiler would accept any arguments to a function.

Suppose that a function called MultFloat() accepts two float arguments and returns the product of the two arguments as a float. Using an early version of C that does not have function prototypes, you could pass two integers to MultFloat(). These arguments would be passed unchanged, and MultFloat()—unaware of the wrong argument types—would return a bogus value or signal a floating-point error.

A function prototype consists of three major parts:

The return value. If the function returns nothing, the prototype should have a return type of void.

The function’s name. I recommend that you use mixed case and no underscores. Underscores can be a problem with linkers that allow only six significant characters.

The function’s parameters. Be explicit about size and type when possible. If you can, include the variable name that will be used by the function because the name implies what the argument does.

The function prototype is the declaration of the function. The function itself is defined (and has a body) later in the program or in a different source file.

Following is a function prototype for a function that compares two strings:

int OurStrCmp(void far *, void far *);

In this function prototype, a function returns an integer. The size of this integer is unimportant and therefore undefined—it could be short or long, depending on the compiler’s default integer size. If the size of the returned value is important, you must specify the size. OurStrCmp() returns a value that is only less than zero, zero, or greater than zero.

Both of the parameters passed to the function are defined as pointers to type void. Here, the void type means the pointers have no specific type, and any pointer type can be passed. If your function expects only a character string pointer, specify this in your function prototype. If the arguments will not be modified when passing pointers, specify this also using the const keyword.

498

All About Header Files

C C C

 

13C

 

C C C

 

C C

Because OurStrCmp() only compares strings, the prototype could be more specific. Rewriting the function prototype for OurStrCmp() results in the following:

short int OurStrCmp(const char far *, const char far *);

Now the function prototype is more complete. However, let’s add the variable names to make it more readable:

short int OurStrCmp(const char far * szStringA, const char far * szStringB);

This prototype is more detailed and allows the compiler to check the types of the arguments passed to the function. In addition, when the function is created, the prototype is used to check whether the function has been properly declared.

If you write your prototypes like the one presented here, the easiest way to write the function for that prototype is to start with the prototype, delete the ending semicolon, and add the function’s opening and closing braces. Although many prototypes are written on one line, a function’s declaration is commonly written with each argument on a new line, as follows:

short int OurStrCmp(

/* Returns

the result of the compare */

const char far *

szStringA,

/*

The

first string to compare */

const char far *

szStringB)

/*

The

second string to compare */

{

/* The body of the function */

} /* end: OurStrCmp() */

This function declaration fully documents the return value and the parameters.

When you create a header file, provide for the possibility that the header file is included more than once. A typical way to do this is to create an identifier; if the identifier exists, the header file has already been included. This could be coded as follows:

#ifndef

_MYHEADER

#define

_MYHEADER

/* Other

lines in this header file */

#endif /* _MYHEADER */

The _MYHEADER identifier must remain unique. This technique prevents errors from symbols defined more than once.

499

Part III • Working with Others

The ANSI C Header Files

ANSI C compilers contain a number of standard header files. These files are used for specific purposes—try not to include header files if you will not be using their functionality. For example, if your program does not have any time-based functions, including time.h will not improve your program but will slow the compiler.

Table 13.1 lists some common identifiers. The table includes both defined identifiers and those that are integral parts of the C language.

Table 13.1. Typical header file identifiers.

Identifier

Description

size_t

An identifier that is guaranteed to hold the size of any

 

definable data object. This identifier is usually defined as

 

type unsigned int.

far

near

_ _FILE_ _

_ _LINE_ _

const

volatile

With segmented (PC 80x86) architecture, a 32-bit pointer. Usually consists of a segment (or selector) and an offset.

With segmented (PC 80x86) architecture, a 16-bit pointer. Usually consists of an offset, without any segment (or selector) information. The object being identified is in the default segment.

The filename of the current file (and header files that have been included).

The current line number of the current file. Each included header file has its own number.

A modifier that tells the compiler that the variable should be treated as a constant and should not be modified.

A modifier that tells the compiler that the variable may be changed in a way that the compiler cannot detect. Examples of undetectable changes are when the variable is modified by an interrupt handler or by a function that uses setjmp().

500

All About Header Files

C C C

 

13C

 

C C C

 

C C

The rest of this chapter describes the standard C header files. Header files specific to particular C compilers are not included in the discussion. To learn about compilerspecific header files, refer to your compiler’s documentation and look at the files themselves.

Your compiler may not contain all the header files described in this chapter. If that is the case, the contents of the header file (or files) are probably included in another header file. A likely choice is the stdlib.h file, which often serves as a catchall.

The assert.h File (ANSI)

The assert.h header file is used for the assert() macro. Note that assert() is always implemented as a macro and is never directly implemented as a function.

You can test a condition with the assert() macro. If the condition tests as TRUE, nothing happens. If the condition tests as FALSE, the following message is printed to

stderr:

Assertion failed: condition, filename, linenumber

The condition is printed as a text string, along with the source file name and the current line number in the current file. After the message is printed, the program calls abort() to end the program—a failed assert() definitely ends your program!

To turn off the effect of the assert() macro, you must define the NDEBUG identifier. When this identifier is defined, assert() evaluates as ((void)0), which is effectively nothing.

The typical definition of the assert() macro is

#define assert(exp)((exp) ? (void) 0 : \ _assert(#exp,_ _FILE_ _,_ _LINE_ _) )

If the expression evaluates to FALSE, the condition, filename and line number in the assert() macro are passed to a function. If the condition evaluates to TRUE, the macro evaluates to ((void)0).

The assert() macro is a valuable tool when you are debugging your program, but you must remember to define NDEBUG when creating the production version of the program.

501

Part III • Working with Others

The ctype.h File (ANSI)

The ctype.h header file contains the character conversion functions that work with a single character. For conversion functions that use strings, see the string.h header file. A character can be classified as any one of the types shown in Table 13.2.

Table 13.2. Common character type identifiers not part of the ANSI standard.

Identifier Description

_UPPER

_LOWER

_DIGIT

_SPACE

An uppercase letter

A lowercase letter

A digit (0–9)

A tab, a carriage return, a newline, a vertical tab, or a form feed

_PUNCT

_CONTROL

_BLANK

_HEX

A punctuation character

A control character

A space character

A hexadecimal digit (0–9, a–f, A–F)

The following functions are defined in the ctype.h header file. Although these functions are defined with a parameter type of int, they are typically passed a parameter of char. The compiler performs the necessary conversion.

isalpha()

Returns TRUE if the character is alphabetic

isupper()

Returns TRUE if the character is uppercase

islower()

Returns TRUE if the character is lowercase

isdigit()

Returns TRUE if the character is a numeric digit

isxdigit()

Returns TRUE if the character is a hexadecimal digit

isspace()

Returns TRUE if the character is a whitespace character

ispunct()

Returns TRUE if the character is a punctuation character

502

 

All About Header Files

C C C

 

 

13C

 

 

C C C

 

 

C C

isalnum()

Returns TRUE if the character is alphabetic or numeric

isprint()

Returns TRUE if the character is a printable character

isgraph()

Returns TRUE if the character is a nonspace printable

 

character

 

iscntrl()

Returns TRUE if the character is a control character

 

toupper()

Converts the character to uppercase

 

tolower()

Converts the character to lowercase

 

_tolower()

Converts the character to lowercase

 

_toupper()

Converts the character to uppercase

 

Many of these functions are also defined as macros. See Table 13.3. These macros are used unless they are undefined using the #undef statement, which must be included after the ctype.h header file is included.

Table 13.3. Character classification macros.

Macro

Definition

isalpha(_c) isupper(_c) islower(_c) isdigit(_c) isxdigit(_c) isspace(_c) ispunct(_c) isalnum(_c) isprint(_c)

isgraph(_c)

iscntrl(_c)

((_ctype+1)[_c] & (_UPPER|_LOWER) ) ((_ctype+1)[_c] & _UPPER ) ((_ctype+1)[_c] & _LOWER ) ((_ctype+1)[_c] & _DIGIT ) ((_ctype+1)[_c] & _HEX ) ((_ctype+1)[_c] & _SPACE ) ((_ctype+1)[_c] & _PUNCT )

((_ctype+1)[_c] & (_UPPER|_LOWER|_DIGIT) )

((_ctype+1)[_c] & (_BLANK|_PUNCT|_UPPER|_LOWER|_DIGIT) )

((_ctype+1)[_c] & (_PUNCT|_UPPER|_LOWER|_DIGIT) )

((_ctype+1)[_c] & _CONTROL )

continues

503

Part III • Working with Others

Table 13.3. continued

Macro

Definition

toupper(_c)

((islower(_c)) ? _toupper(_c) : (_c) )

tolower(_c)

((isupper(_c)) ? _tolower(_c) : (_c) )

_tolower(_c)

((_c)-'A'+'a' )

_toupper(_c)

((_c)-'a'+'A' )

_ _isascii(_c)

((unsigned)(_c) < 0x80 )

_ _toascii(_c)

((_c) & 0x7f )

 

 

The character classification macros reference an array of bytes called _ctype. The bits in this array are set based on the character’s classification. This allows a fast test of a character’s attributes in a macro.

Both the toupper() and tolower() functions return the correctly converted character or the supplied character if there is no conversion. It is no longer necessary to check whether the character is uppercase or lowercase first.

The errno.h File (ANSI)

The errno.h header file has identifiers for the error codes returned by the errno() function. C compilers may define different values for each identifier, so you should never hard code an integer constant—use the identifier instead.

The errno() function is generally coded as a function, then defined to appear as a variable called errno. Table 13.4 lists the common values for errno.

Table 13.4. Typical errno values.

Error code

Description

E2BIG

EACCES

The argument list is too long.

You cannot access the file, probably because the file is not compatible with your request or the file has an attribute (such as read only) that is incompatible with your request.

504

All About Header Files

C C C

 

13C

 

C C C

 

C C

Error code

Description

EAGAIN EBADF

You cannot create any more child processes.

The specified file number is invalid (probably not a currently opened file), or the file is opened in a mode incompatible with the requested action.

EDEADLOCK

The resource could not be locked (after a preset number of tries), and a resource deadlock would occur.

EDOM

The argument to a math function is not in the domain of the function.

EEXIST EINVAL EMFILE ENOENT ENOEXEC ENOMEM ENOSPC ERANGE

The file that is to be created already exists.

The specified argument is invalid.

Too many files are open.

The file or directory cannot be found.

The file that was to be executed was not an executable file.

There is not enough RAM.

The disk drive is full.

The argument to a math function was too large, resulting in a partial or total loss of significance.

EXDEV

An attempt was made to rename (using rename()) a file to a

 

new directory on a different drive.

 

 

Other errno values are specific to the environment or compiler. The use of errno is generally defined in a function’s error conditions. For example, the description for the read() function includes information that errno may be set to EBADF if a bad file handle is encountered.

Include

Syntax

<io.h>, <errno.h>

int read( int handle, void *buffer, unsigned int count );

505