Appendix A. UNIX Fundamentals

Manual Pages

The programs in this book are based on the Single UNIX Specification, Version 3. We refer to this specification by its IEEE name, POSIX. Essentially identical documents have been published by three standards organizations, the IEEE [49, 50, 51, 52], ISO/IEC [57], and the Open Group [89]. The IEEE and ISO/IEC publish print and electronic versions of the standard that are available for a fee. The Open Group publishes the standard on CD-ROM, but this organization also makes the standard freely available on their web site, http://www.UNIX-systems.org/single_unix_specification/. You must register the first time you enter the web site, but it is open to the public at no charge. The standard is organized into the following four parts.

  1. Base Definitions: general terms and concepts, header files

  2. System Interfaces: definitions of functions

  3. Shell and Utilities: definitions of commands

  4. Rationale: discussion of historical information and why features were or were not included in the standard

Use section 2 of the standard to find out about system calls and library functions such as pipe and socket. Look in section 3 for information about commands, such as ls and cat, that can be executed from the shell.

Most UNIX systems have online documentation called the man pages. Here, “man” stands for “manual” as in system manual. The man utility displays these pages of online documentation in a readable format.

SYNOPSIS

   man [-k] name
                                    POSIX:Shell and Utilities

Unfortunately, the standard does not require much functionality from the manual facility. If name is a standard utility, the standard requires only that a message describing its syntax, options and operands be displayed. The -k option lists the summaries of manual entries that contain name.

Most UNIX implementations divide the manual pages into sections, with typical section numbers shown in Table A.1. The first three sections are of most interest to us. Most implementations of man display only the information about the first occurrence of an entry. For example, write of section 1 is a command that can be executed from the shell to send a message to a terminal of another user. Users of this book would probably be more interested in the write description of section 2, which is the library function described in Section 4.2. Most implementations of man provide an option called -a to display all manual entries and an option called -s or -S to display only entries from a given section for the manual.

Table A.1. Typical sections numbers for UNIX man pages.

section

contents

1

user commands

2

system calls

3

C library functions

4

devices and network interfaces

5

file formats

6

games and demos

7

environments, tables and troff macros

8

system maintenance

Example A.1. 

The following command can be used under Solaris to display the manual entry for write from section 2.

man -s 2 write

Under Linux or Mac OS X the corresponding command is the following.

man -S 2 write

Figure A.1 shows the typical output of the man utility when the man tee command executes. The first line or header line of the man page gives the name of the command followed in parentheses by the man page section number. The tee(1) in Figure A.1 refers to the tee command described in section 1 of the man pages. Do not try to execute tee(1). The (1) suffix is not part of the command name, rather it is a man page section indicator.

Example A.1. Typical man page listing for the tee command.

tee(1)                    User Commands                   tee(1)

NAME
     tee - duplicate standard output

SYNOPSIS
     tee [ -ai ] [ file ... ]

DESCRIPTION
     The tee utility shall copy standard input to standard
     output, making a copy in zero or more files. The tee utility
     shall not buffer output. The options determine if the
     specified files are overwritten or appended to.

OPTIONS
     The following options shall be supported.

     -a Append the output to the files rather than overwriting them.

     -i Ignore the SIGINT signal.

OPERANDS
     The following operands are supported:

     file  A pathname of an output file. Processing of at least
           13 file operands shall be supported.

ENVIRONMENT VARIABLES
     ...

EXIT STATUS
     The following exit values are returned:

     0     The standard input was successfully copied to all output files.

     >0 The number of files that could not be opened or whose
           status could not be obtained.

APPLICATION USAGE
     The tee utility is usually used in a pipeline, to make a
     copy of the output of some utility.

     The file operand is technically optional, but tee is no more
     useful than cat when none is specified.

EXAMPLES
     Save an unsorted intermediate form of the data in a pipeline:
     ... | tee unsorted | sort > sorted

SEE ALSO
     cat(1), attributes(5), environ(5)

Each man page covers some aspect of UNIX (e.g., a command, a utility, a library call). The individual man pages are organized into sections like the tee man page of Figure A.1. Some common section titles are given in Table A.2.

Table A.2. Typical sections of a UNIX man page.

section title

contents

HEADER

title for the individual man page

NAME

one-line summary

SYNOPSIS

description of usage

EXIT STATUS

values returned on exit from a command

DESCRIPTION

discussion of what the command or function does

RETURN VALUES

possible return values

ERRORS

summary of errno values and conditions for errors

FILES

list of the system files that the command or function uses

SEE ALSO

list of related commands or additional sections of the manual

ENVIRONMENT

list of relevant environment variables

NOTES

information on unusual usage or implementation features

BUGS

list of known bugs and caveats

The name section of a man page lists the names of the items described on that man page. The man pages contain information about many types of items. The man page on write(1) describes a command, and the man page on write(2) describes a library function. The two write entries have completely different purposes. Look at the synopsis section to determine which write you want. The synopsis summarizes how a command or function is invoked. The synopsis for a library function has function prototypes along with the required header files. The write(2) function is called from a C program. In contrast, write(1) is executed from the command prompt or from a shell script.

In addition to the standard documents and manual pages, many UNIX vendors make detailed documentation accessible through the Web. Sun provides documentation at http://docs.sun.com. The Linux Documentation Project web page, http://tldp.org/, has the Linux manual pages, HOWTO guides and other information. Apple provides documentation for Mac OS X on their developer’s web site, http://developer.apple.com.

Compilation

The C compiler, cc, translates a collection of C source programs and object files into either an executable file or an object file. On your system, the compiler may have another name, such as gcc. The cc command may be a symbolic link to another executable.

Compilation proceeds in stages. In the first stage, a preprocessor expands macros and includes header files. The compiler then makes several passes to translate the code, first to the assembly language of the target machine and then into machine code. The result is an object module, which has machine code and tables of unresolved references. The final stage of compilation links a collection of object modules together to form the executable module with all references resolved. An executable file is ready to be loaded and run. The executable contains exactly one main function.

Example A.2. 

The following command compiles mine.c and produces the executable mine.

cc -o mine mine.c

If the -o mine option is omitted, the C compiler produces an executable called a.out. Use the -o option to avoid the noninformative default name.

Example A.3. 

The following mine.c source file contains an undefined reference to the serr function.

void serr(char *msg);

int main(void) {
   serr("This program does not do much
");
   return 0;
}

When mine.c of Example A.3 is compiled as in Example A.2, the C compiler displays a message indicating that serr is an unresolved reference and does not produce an executable.

Programs are usually organized into multiple source files that must be linked together. You can compile all the source files with a single cc command. Alternatively, you can compile the source into separate object modules and link these object modules to form an executable module in a separate step.

Example A.4. 

Suppose that the serr function is contained in the source file minelib.c. The following command compiles the mine.c source file of Example A.3 with minelib.c to produce an executable module called mine.

cc -o mine mine.c minelib.c

The -c option of cc causes the C compiler to produce an object module rather than an executable. An object module cannot be loaded into memory or executed until it is linked to libraries and other modules to resolve references. The C compiler does not complain about unresolved references in object modules. A misspelled variable or missing library function might not be detected until that object module is linked into an executable.

Example A.5. 

The following command produces the object module mine.o.

cc -c mine.c

When the -c option is used, the C compiler produces an object module named with the .o extension. The mine.o produced by the cc command of Example A.5 can later be linked with another object file (e.g., minelib.o) to produce an executable.

Example A.6. 

The following command links the object modules mine.o and minelib.o to produce the executable mine.

cc -o mine mine.o minelib.o

Header files

Before a function such as serr in Example A.3 is referenced, it should either be defined or have a prototype. Often, prototypes are contained in header files.

Before compilation, the C preprocessor copies the header files specified by #include statements into the source. By convention, header files have a .h extension. Put declarations of constants, types and functions in header files. Do not put variable declarations in header files, because this can result in multiply-defined variables. The next exercise illustrates the difficulties caused by placing variable declarations in header files.

Example A.7. 

What happens if you execute the following commands?

cc -o mystuff my.c mylib.c
mystuff

The file myinc.h contains the following segment.

#include <stdio.h>
static int num;
void changenum(void);

The file my.c contains the following main program.

#include "myinc.h"
int main (void) {
   num = 10;
   changenum();
   printf("num is %d
", num);
   return 0;
}

The file mylib.c contains the following function.

#include "myinc.h"
void changenum(void) {
   num = 20;
}

Answer:

Both my.c and mylib.c contain a num variable because its definition appears in myinc.h. The call by the main program to changenum does not affect the value of the variable num defined in my.c. The mystuff program outputs 10 rather than 20.

Enclose system-defined header files in angle brackets (as in #include <stdio.h>) since the compiler then looks in the standard place for the file. The standard place depends on the system, but the man page for cc usually describes how the standard search occurs. The /usr/include directory holds many of the standard header files. The files in this directory often include other .h files from subdirectories beneath /usr/include. The /usr/include/sys directory is a standard location for many of the .h files needed for this book. Be sure to include the header files specified by the man page synopsis when using a library function. Enclose personal header filenames in double quotes as follows.

#include "myinc.h"

The quotes tells the compiler to look for the header file in the directory containing the source file before looking in the standard place.

Example A.8. 

A program uses the error symbol EAGAIN in conjunction with a call to write. The compiler complains that EAGAIN is not defined. Now what?

Answer:

Try the following steps to solve the problem.

  • Make sure to include all the header files mentioned in the synopsis for write. The man page specifies the header file <unistd.h>.

  • Buried somewhere in the man pages is a statement mentioning that errno.h must be included in programs that refer to error symbols. If the program includes errno.h, the problem is solved.

  • If the errno.h statement in the man page escapes your notice, look for the symbol EAGAIN directly in the system header files by using

    cd /usr/include
    grep EAGAIN *
    

    The grep command searches for the string EAGAIN in all of the files in the directory /usr/include. Unfortunately, the EAGAIN symbol is not in any of the files in /usr/include.

  • Change to the /usr/include/sys directory and try grep again. The following is a typical response to grep.

    errno.h:#define EAGAIN 11
    errno.h:#define EWOULDBLOCK        EAGAIN
    

    It might be tempting to eliminate the problem by including the file sys/errno.h in the source, but what the compiler really wants is errno.h. Using errno.h directly is better because it includes sys/errno.h and also contains additional definitions.

Linking and libraries

Just because a program has the right header files does not mean that your troubles are over. A header file gives symbol declarations and function prototypes, but it does not supply the actual code for the function call.

Example A.9. 

The mylog.c source file calculates the logarithm of a value. After including math.h in that source file, the user compiles the program and receives an error message that the log function could not be found. Why not?

Answer:

The math.h header file just tells the C compiler what the form (prototype) of the log function is. It does not actually supply the function.

Compilation takes place in two distinct phases. In the first phase, the compiler translates each C source file into object code. The cc -c option stops at this point. Object code is not ready to execute because the program may reference outside items that have not been located. To produce an executable module, the compile must find all the undefined symbols (unresolved external references). The cc compiler calls the link editor, ld, to accomplish this task.

Example A.10. 

The following command compiles the mylog.c source file with the system math library to produce an executable called mylog.

cc -o mylog mylog.c -lm

To use C mathematics library functions, put #include <math.h> in the source file and also specify that the program should be linked with the math library (-lm) when it is compiled.

The names of libraries are specified by the -l option. The object files are processed in the order in which they appear on the cc command line, so the location of -l on the cc line is significant. It should come after the object files because only those entries that match unresolved references are loaded. By default, the link editor automatically searches the standard C library.

Example A.11. 

What happens if the math library in Example A.10 is linked, but the header file math.h is not included in the source?

Answer:

The compiler assumes that log has a return value of type int rather than double. If the program calls the log function, the calculation produces an incorrect numerical result. The compiler may not produce an error or warning message. However, lint (Section A.4) reports that log has been implicitly declared to return int.

Example 1.12. 

The following linking command processes the object files in the order my.o, the math library, and then mylib.o.

cc -o my my.o -lm mylib.o

The link editor includes only those objects in the library that correspond to unresolved references. Thus, if mylib.o contains a reference to the math library, that reference is not resolved by this command.

The -lx option is short for either libx.a (a library archive) or libx.so (a shared library). Which is the default depends on how the system is set up. Many compilers allow you to specify -Bstatic -lx in the cc command for a library archive and -Bdynamic -lx for a shared library. The compiler scans the shared libraries for references, but it does not actually put the functions in the executable output file. Instead, the runtime system loads them by dynamic loading and binding.

Several versions of a particular library may coexist on a system—at least one for each version of the C compiler. A typical search order for libraries is the following.

  • -L directories specified on the cc line

  • Directories in the LD_LIBRARY_PATH environment variable

  • Standard library directories (e.g., /usr/lib)

The -L option of cc explicitly specifies pathnames for directories to be searched for libraries. The LD_LIBRARY_PATH environment variable specifies default pathnames for searching for load libraries. Generally, LD_LIBRARY_PATH includes pathnames for the directories in which the compilers are installed, as well as directories such as /usr/local/lib. Your system administrator has probably set up the LD_LIBRARY_PATH variable for using the standard compilers.

Macros and conditional compilation

Before the Single UNIX Specification, there were several incompatible UNIX standards, and vendors would use conditional compilation to adjust for these differences. The preprocessor can produce different code for the compiler from a single source file through the use of the #if, #ifdef and #ifndef preprocessor statements. Such conditional compilation can be used to allow a program to be compiled under different implementations or in different environments.

Example A.13. 

The UICI restart library sets errno to ETIME when the function waitfdtimed times out. Some systems do not define ETIME but instead use the error ETIMEDOUT. The file restart.h solves this problem with the following.

#ifndef ETIME
#define ETIME ETIMEDOUT
#endif

If ETIME is not already defined, it is defined as ETIMEDOUT.

ETIME and ETIMEDOUT are examples of simple macros specified by a #define statement. The preprocessor replaces these defined constants with their values before passing the code to the C compiler.

Most C compilers have a -D option that allows the setting of macros at compile time.

Example A.14. 

The Linux header files provide a number of options to support different standards and implementations. Linux uses the constant _GNU_SOURCE for many of the features that are now part of the Single UNIX Specification. If this constant is defined, then these features are turned on. Some of the programs in this book require this constant to be defined when the programs are compiled under Linux. To compile the program myprog.c with this constant defined, use the following command.

cc -D_GNU_SOURCE -o myprog myprog.c

This causes the constant _GNU_SOURCE to be defined with the default value of 1, as if the following statement appeared as the first line of the source file.

#define _GNU_SOURCE 1

Example A.15. 

The UICI name library in Section C.2 gives four implementations of the function addr2name and name2addr, using conditional compilation to choose one of the implementations. The general format of the code is as follows.

#ifndef REENTRANCY
#define REENTRANCY_NONE
#endif

#if REENTRANCY==REENTRANT_NONE
   /* default code using gethostbyname and gethostbyaddr */
#elif REENTRANCY==REENTRANT_R
   /* code using gethostbyname_r and gethostbyaddr_r */
#elif REENTRANCY==REENTRANT_MUTEX
   /* code using mutex locks */
#elfi REENTRANCY==REENTRANT_POSIX
   /* code using getnameinfo and getaddrinfo */
#endif

The first three lines guarantee that REENTRANCY has its default value if it is not otherwise defined.

Example A.16. 

Execute the following command to compile the program client.c with the restart library, the UICI library, and the UICI name library. Use the getnameinfo and getaddrinfo functions.

cc -DREENTRANCY=REENTRANT_POSIX -o client client.c restart.c uiciname.c uici.c

Additional libraries may be needed on your system.

Makefiles

The make utility, which allows users to incrementally recompile a collection of program modules, is convenient and helps avoid mistakes. To use make, you must specify dependencies among modules in a description file. The make utility uses the description file to see if anything needs updating.

The description file specifies dependency relationships that exist between targets and other components. Lines starting with # are comments. The dependencies in the description file have the following form.

target:          components
TAB              rule

The first line is called a dependency, and the second line is called a rule. The first character on a rule line in a description file must be the TAB character. A dependency may be followed by one or more rule lines.

The default description filenames are makefile and Makefile. When the user types make with no additional arguments, the make utility looks for makefile or Makefile in the current directory to use as its description file.

Example A.17. 

In Example A.6, the executable mine depends on the object files mine.o and minelib.o. The following description specifies that dependency relationship.

mine:   mine.o minelib.o
        cc -o mine mine.o minelib.o

The dependency relationship specifies that the target mine should be updated by executing the rule cc -o mine mine.o minelib.o if either mine.o or minelib.o has been modified since mine was last changed,

A dependency graph for the makefile of Example A.18.

Figure A.2. A dependency graph for the makefile of Example A.18.

Example A.18. 

A makefile target may depend on components that are themselves targets. The following makefile description file has three targets.

my:     my.o mylib.o
        cc -o my my.o mylib.o

my.o:   my.c myinc.h
        cc -c my.c

mylib.o:  mylib.c myinc.h
        cc -c mylib.c

The target my depends on the targets my.o and mylib.o. Just type make to do the required updates.

Sometimes it is helpful to visualize the dependencies of a description file by a directed graph. Use graph nodes (with no duplicates) to represent the targets and components. Draw a directed arc from node A to node B if target A depends on B. A proper description file’s graph should have no cycles. Figure A.2 shows the dependency graph for the description file of Example A.18.

Description files can also contain macro definitions of the following form.

NAME = value

Whenever $(NAME) appears in the description file, make substitutes value before processing. Do not use tabs in macros.

Example A.19. 

The following description file uses a macro to represent the compiler options. With this definition, the compiler options need only be changed in a single place rather than in the entire file.

OPTS = -g

my:     my.c  my.h
        cc $(OPTS) -o my my.c

The make command also allows the name of a target to be specified on the command line. In this case, make updates only the specified target. When developing multiple targets in the same directory (e.g., send and receive programs), use this feature to debug one target at a time. If no targets are explicitly specified on the command line, make checks only the first target in the description file. Often, a description file has a first target called all that depends on all the other targets.

Example A.20. 

The following command causes make to update only the target my.

make my

The command of Example A.20 does not interpret my as a description file but as a target within the default description file (either makefile or Makefile in the current directory).

Use the -f option with make for description files with names other than makefile or Makefile.

Example A.21. 

The following command updates target1 from the description file mymake.

make -f mymake target1

Debugging Aids

This section discusses the lint utility, debuggers, the truss utility and profiling.

The lint utility

The lint utility finds errors and inconsistencies in C source files. The lint program performs type checking, tries to detect unreachable statements, and points out code that might be wasteful or nonportable; lint also detects a variety of common errors, such as using = instead of == or omitting & in arguments of scanf. You should call lint for all programs. Pay attention to the resulting warning messages, since lint is pickier than the C compiler in many areas. The C compiler presumes that programs have already been linted and is usually implemented to be fast rather than fussy.

Example A.22. 

Add the following lines to the description file of Example A.18 to lint the sources.

lintall:
           lint my.c mylib.c > my.lint

Type make lintall to lint the programs. The output of lint is in my.lint.

Example A.23. 

How should the following lint message be interpreted?

implicitly declared to return int:
    (14) strtok

Answer:

This lint message warns that the program did not include the string.h header file associated with strtok appearing on line 14 of the source file. Lacking information to the contrary, the compiler assumes that strtok returns int. Unfortunately, strtok returns char*. The lack of header can lead to disastrous results at execution time.

Example A.24. 

How should the following lint message be interpreted?

(5) warning: variable may be used before set: p

Answer:

This message usually appears when the program uses a pointer before setting its value, as in the following code segment.

char *p;
scanf("%s", p);

The pointer p is not pointing to an appropriate character buffer. The code may compile, but the program will probably produce a segmentation error when executed.

Debuggers

Debuggers are runtime programs that monitor and control the execution of other programs. Common debuggers found in UNIX environments are dbx, adb, sdb and debug. Debuggers allow a user to single-step through a program and monitor changes to specified variables. To use a debugger, compile the program with the -g option.

Example A.25. 

Compile the program my.c with the -g option as follows to instrument the executable for debugger control.

cc -g -o my my.c

Run my under the dbx debugger by typing the following command.

dbx my

The debugger responds with the following prompt.

(dbx)

Respond with help for a list of commands or run to run the program. Set a stopping point with stop, or turn on tracing when a variable changes, by typing trace before typing run.

Many programmers, especially beginning programmers, find debuggers useful for pointer problems. Some debuggers have graphical user interfaces that make them easier to use. Standard debuggers are less useful in a concurrent environment, in which processes interact or timing can change the behavior of a program. Thread debuggers are also available on a limited basis. Debuggers may help you find a particular execution error, but using a debugger is no substitute for having a program test plan. Good error trapping for function calls is probably the most valuable debugging strategy to follow.

The truss utility

For runtime debugging, the truss command is useful if it is available. The truss command produces a trace of system calls that are made and the signals delivered while a particular process is running. Use the -f option with truss to trace the calls of all children of the process. The truss command is not part of POSIX and is not available on all systems.

Example A.26. 

Suppose that a program called dvips is installed on a system and that this program accesses the psfonts.map file. You have placed a copy of psfonts.map in the bin subdirectory of your home directory. When you run the program, you receive the following error message.

unable to open file

How can you figure out how to correct the problem?

Answer:

Try executing the following command (from a C shell).

truss dvips -f t.dvi |& grep psfonts.map

The truss program runs the command dvips -f t.dvi, and grep displays the output lines containing psfonts.map. The |& argument causes both the standard output and the standard error of truss to be piped to the standard input of grep. The output might appear as follows.

open("./psfonts.map", O_RDONLY, 0666)         Err#2 ENOENT
open("/usr/local/tex/dvips/psfonts.map", O_RDONLY, 0666) Err#2 ENOENT

The output reports that the program first looked for psfonts.map in the current directory and then in the directory /usr/local/tex/dvips. Copy the psfonts.map to /usr/local/tex/dvips and everything should be ready to go!

Profilers

Most C compilers have options for profiling programs. Profilers accumulate statistical information such as execution times for basic blocks and frequency of calls. Consult the man pages for prof, gprof, monitor, profil and tcov as well as for cc to obtain additional information about profiling.

Identifiers, Storage Classes and Linkage Classes

Programmers are often confused about the meaning of the keyword static, in part because C uses the word two different ways. The main points to remember are the following.

  1. If static is applied to a function, that function can only be called from the file in which it is defined.

  2. If a variable definition appears outside any block, the variable exists for the duration of the program. If static is applied, the variable can only be accessed from within the file containing the definition. Otherwise, the variable can be accessed anywhere in the program.

  3. If a variable is defined inside a block, it can only be accessed within the block. If static is applied, the variable exists for the duration of the program and it retains its value when execution leaves the block. Otherwise, the variable is created when the block is entered, and it is destroyed when execution leaves the block. Such a variable needs to be explicitly initialized before it can be used.

These rules are based on C’s notion of scope of an identifier and linkage, which we now discuss.

According to the ISO C standard, “An identifier can denote an object; a function; a tag or member of a structure, union, or enumeration; a typedef name; a label name; a macro name; or a macro parameter.” [56, section 6.2.1] Here, we mainly discuss identifiers that are associated with variables and functions.

An identifier can be used only in a region of program text called its scope. If two different entities are designated by the same identifier, their scopes must be disjoint, or one scope must be completely contained in the other. In the inner scope, the other entity is hidden and cannot be referenced by that identifier.

The scope begins at the identifier declaration. If the declaration occurs inside a block, the identifier has block scope and the scope ends at the end of the block. If the declaration occurs outside any block, the identifier has file scope, and the scope ends at the end of the file in which it is declared.

Identifiers declared more than once may refer to the same object because of linkage. Each identifier has a linkage class of external, internal or none. Declarations in a program of a particular identifier with external linkage refer to the same entity. Declarations in a file of a particular identifier with internal linkage represent the same entity. Each declaration of an identifier with no linkage represents a unique entity.

An identifier representing a function has external linkage by default. This means that it can be referenced in any file of the program. Referencing it in a file other than the one in which it is defined requires a function prototype. You can hide a function from other files by giving it internal linkage, using the static qualifier.

An identifier representing an object (such as a variable) has a linkage class related to its storage class, also called storage duration. The storage duration determines the lifetime of the object, the portion of the program execution for which storage is guaranteed to be reserved for the object. There are three storage durations: static, automatic and allocated. Allocated objects have a lifetime that begins with a successful malloc or related function and ends when the object is explicitly freed or the program terminates. The lifetimes of other objects are determined by the declaration of the corresponding identifier.

An identifier of an object declared outside any block has static storage class. Objects with static storage class have a lifetime that is the duration of the program. They are initialized once and retain their last stored value. If no explicit initialization is given in the declaration, they are initialized to 0. As with functions, these identifiers have external linkage by default but can be given internal linkage by means of the static qualifier.

An identifier of an object declared inside a block has no linkage. Each identifier denotes a unique object. These identifiers have automatic storage duration by default. Objects with automatic storage class have a lifetime that begins when execution enters the block and ends when execution exits the block. These objects are not initialized by default and do not necessarily retain their last stored value after execution exits the block. If the block is entered through recursion or with multiple threads, each entry into the block creates a distinct object. A variable with automatic storage class is called an automatic variable.

An identifier of an object declared inside a block can be given static storage duration with the static qualifier. The object then has a lifetime that is the duration of the program and retains its last stored value. If the block is entered through recursion or multiple threads, the same object is used.

Objects with identifiers having static storage duration are often called static variables; those with identifiers having automatic storage duration are called automatic variables.

As described above, the static qualifier can affect either the storage class or linkage class of an object depending on the context. When static is applied to a function, it always changes its linkage class from the default of external to internal. Functions do not have a storage duration. For objects declared inside a block, the linkage class is always none and static changes the storage class from automatic to static. For objects declared outside any block, the storage class is always static and the static specifier changes the linkage class from external to internal. These rules are summarized in Table A.3.

Table A.3. Effect of using the static keyword modifier on an object in a C program.

where declared

static modifies

static applied?

storage class

linkage class

inside a block

storage class

yes

static

none

inside a block

storage class

no

automatic

none

outside any block

linkage class

yes

static

internal

outside any block

linkage class

no

static

external

Additional Reading

UNIX SYSTEM V: A Practical Guide, 3rd ed., by Sobell [108] is an up-to-date reference on using the UNIX utilities. UNIX System Administration Handbook, 3rd ed., by Nemeth et al. [86] is an excellent and readable introduction to many of the configuration issues involved in setting up UNIX systems. O’Reilly Press has individual books on many of the topics in this appendix including emacs [20], the libraries [27], lint [28], make [120], and vi [69].

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset