2.1 Source Files and Source Programs

A source program can be divided into one or more “source files,” or “translation units.” The input to the compiler is called a “translation unit.”

Syntax

translation-unit :
external-declaration
translation-unit external-declaration

external-declaration
:
function-definition
declaration

“Overview of Declarations” gives the syntax for the declaration nonterminal, and “Phases of Translation” explains how the translation unit is processed.

Note:

See the introduction to Appendix B for an explanation of the ANSI grammar conventions.

The components of a translation unit are external declarations that include function definitions and identifier declarations. These declarations and definitions can be in source files, header files, libraries, and other files the program needs. You must compile each translation unit and link the resulting object files to make a program.

A C “source program” is a collection of directives, pragmas, declarations, definitions, statement blocks, and functions. To be valid components of a Microsoft C program, each must have the syntax described in this manual, although they can appear in any order in the program (subject to the rules outlined throughout this manual). However, the location of these components in a program does affect how variables and functions can be used in a program. (See “Understanding Lifetime, Scope, Visibility, and Linkage” for more information.)

Source files need not contain executable statements. For example, you may find it useful to place definitions of variables in one source file and then declare references to these variables in other source files that use them. This technique makes the definitions easy to find and update when necessary. For the same reason, constants and macros are often organized into separate files called “include files” or “header files” that can be referenced in source files as required. (“Manifest Constants and Macros” explains macros. See topic for information about include files.)

Preprocessor Directives

A “directive” instructs the C preprocessor to perform a specific action on the text of the program before compilation. Preprocessor directives are fully described in Chapter 7, “Preprocessor Directives and Pragmas.” This example uses the preprocessor directive #define:

#define MAX 100

This statement tells the compiler to replace each occurrence of MAX by 100 prior to compilation. The C compiler preprocessor directives are

#define#elif#else#endif#error#if#ifdef#ifndef#include#line#pragma#undef

Pragmas

A “pragma” instructs the compiler to perform a particular action at compile time. Pragmas vary from compiler to complier. For example, you can use the optimize pragma to set the optimizations to be performed on your program.

Microsoft Specific

The Microsoft C pragmas arealloc_textauto_inlinecheck_pointercheck_stackcode_segcommentdata_segfunctionhdrstopinline_depthinline_recursionintrinsiclinesizemessagenative_calleroptimizepackpagepagesize skipsubtitletitlewarning

These pragmas are described in “Pragma Directives”.

Declarations and Definitions

A “declaration” establishes an association between a particular variable, function, or type and its attributes. “Overview of Declarations” gives the ANSI syntax for the declaration nonterminal. A declaration also specifies where and when an identifier can be accessed (the “linkage” of an identifier). See “Understanding Lifetime, Scope, Visibility, and Linkage” for information about linkage.

A “definition” of a variable establishes the same associations as a declaration but also causes storage to be allocated for the variable.

For example, the main, find, and count functions and the var and val variables are defined in one source file, in this order:

main()

{

}

int var = 0;

double val[MAXVAL];

char find( fileptr )

{

}

int count( double f )

{

}

The variables var and val can be used in the find and count functions; no further declarations are needed. But these names are not visible (cannot be accessed) in main.

Function Declarations and Definitions

Function prototypes establish the name of the function, its return type, and the type and number of its formal parameters. A function definition includes the function body.

Both function and variable declarations can appear inside or outside a function definition. Any declaration within a function definition is said to appear at the “internal” or “local” level. A declaration outside all function definitions is said to appear at the “external,” “global,” or “file scope” level. Variable definitions, like declarations, can appear at the internal level (within a function definition) or at the external level (outside all function definitions). Function definitions always occur at the external level. Function definitions are discussed further in “Function Definitions”. Function prototypes are covered in “Function Declarations” and in “Function Prototypes”.

Blocks

A sequence of declarations, definitions, and statements enclosed within curly braces ({ }) is called a “block.” There are two types of blocks in C. The “compound statement,” a statement composed of one or more statements (discussed more fully on page 153), is one type of block. The other, the “function definition,” consists of a compound statement (the body of the function) plus the function's associated “header” (the function name, return type, and formal parameters). A block within other blocks is said to be “nested.”

Note that while all compound statements are enclosed within curly braces, not everything enclosed within curly braces constitutes a compound statement. For example, although the specifications of array, structure, or enumeration elements may appear within curly braces, they are not compound statements.

Example Program

The following C source program consists of two source files. It gives an overview of some of the various declarations and definitions possible in a C program. Later sections in this manual describe how to write these declarations, definitions, and initializations, and how to use C keywords such as static and extern. The printf function is declared in the C header file STDIO.H.

The main and max functions are assumed to be in separate files, and execution of the program begins with the main function. No explicit user functions are executed before main.

/*****************************************************************

FILE1.C - main function

*****************************************************************/

#define ONE 1

#define TWO 2

#define THREE 3

#include <stdio.h>

int a = 1; /* Defining declarations */

int b = 2; /* of external variables */

extern int max( int a, int b ); /* Function prototype */

int main() /* Function definition */

{ /* for main function */

int c; /* Definitions for */

int d; /* two uninitialized */

/* local variables */

extern int u; /* Referencing declaration */

/* of external variable */

/* defined elsewhere */

static int v; /* Definition of variable */

/* with continuous lifetime */

int w = ONE, x = TWO, y = THREE;

int z = 0;

z = max( x, y ); /* Executable statements */

w = max( z, w );

printf( "%d %d\n", z, w );

}

/****************************************************************

FILE2.C - definition of max function

****************************************************************/

int max( int a, int b ) /* Note formal parameters are */

/* included in function header */

{

if( a > b )

return( a );

else

return( b );

}

FILE1.C contains the prototype for the max function. This kind of declaration is sometimes called a “forward declaration” because the function is declared before it is used. The definition for the main function includes calls to max.

The lines beginning with #define are preprocessor directives. These directives tell the preprocessor to replace the identifiers ONE, TWO, and THREE with the numbers 1, 2, and 3, respectively, throughout FILE1.C. However, the directives do not apply to FILE2.C, which is compiled separately and then linked with FILE1.C. The line beginning with #include tells the compiler to include the file STDIO.H, which contains the prototype for the printf function. Preprocessor directives are explained in Chapter 7.

FILE1.C uses defining declarations to initialize the global variables a and b. The local variables c and d are declared but not initialized. Storage is allocated for all these variables. The static and external variables, u and v, are automatically initialized to 0. Therefore only a, b, u, and v contain meaningful values when declared because they are initialized, either explicitly or implicitly. FILE2.C contains the function definition for max. This definition satisfies the calls to max in FILE1.C.

The lifetime and visibility of identifiers are discussed in “Understanding Lifetime, Scope, Visibility, and Linkage”. For more information on functions, see Chapter 6.