Ethical Hacking Programming, Blogging, Hosting, All Computer Software, PC Software Download, JAVA in hindi, HTML, PHP, C, C++, Free Learning, Software's Download, Technical Videos, Technical Tricks and Tips, How Make Money

Scope and Extent in C programming Class 20

Chapter 5

Scope and Extent


The scope of a name refers to the part of the program within which the name can be used. That is, it describes the visibility of an identifier within the program. The extent of a variable or function refers to its lifetime in terms of when memory is allocated to store it, and when that memory is released.

The rules of scope and extent a ect the way functions and data interact, and are central to the design of C programs. This chapter examines the various storage classes that control these properties. Focus the way the scope and extent control facilitate the writing of modular programs, and especially on the way to implement multi-file programs.

5.1 Local Scope and Automatic Extent


A variable declared within a function has local scope by default.1 This means that it is local to the block in which it is defined, where a block is a code segment enclosed in braces {...}. Function arguments also have local scope. For example, in the following function

void afunction(int a, int b)

{

double val;

statements

{

int val2 = 5;

statements

} /* val2 goes out-of-scope here */

statements

} /* a, b, val go out-of-scope here */

the variables a, b, val, and val2 all have local scope. The visibility of a local variable is the block in which it is defined. Thus local variables with the same name defined in di erent blocks or functions are unrelated.

A local variable has automatic extent, which means that its lifetime is from the point it is defined until the end of its block. At the point it is defined, memory is allocated for it on the “stack”; this memory is managed automatically by the compiler. If the variable is not explicitly initialised, then it will hold an undefined value (e.g., in the above, val has an arbitrary value, while val2 is initialised to 5). It is often good practice to initialise a local variable when it is declared. At the end of the block, the variable is destroyed and the memory recovered; the variable is said to go “out-of-scope”.

Local variables are also called automatic variables, and have storage class auto but, as this storage class is the default for variables declared within functions, the keyword auto is redundant and never used in practice.

5.2 External Scope and Static Extent

External variables are defined outside of any work, and thus it is probably available for many tasks. Functions are always external, because C does not allow the function to be defined in other functions [KR88, p. 73]

A variable defined outside of any function is an external variable, by default. External variables and functions are visible over the entire (possibly multi-file) program; they have external scope (also called program scope). This means that a function may be called from any function in the program, and an external variable2 may be accessed or changed by any function. However, it is necessary to first declare a variable or function in each file before it is used.

The extern keyword is used to declare the existence of an external variable in one file when it is defined in another. Function prototypes may also be preceded by extern, but this is not essential as they are external by default. It is important to note the distinction between declaration and definition. A declaration refers to the specification of a variable or function, in particular its name and type. A definition is also a specification, but additionally involves the allocation of storage. A variable or function may be declared multiple times in a program (provided the declarations are non-conflicting) but may be defined only once. An example of external variables and functions shared across two source-files is shown below.


File one.c:
int globalvar; /* external variable definition */
extern double myvariable; /* external variable declaration (defined elsewhere) */
void myfunc(int idx); /* external function prototype (declaration) */

File two.c:

double myvariable = 3.2; /* external variable definition */

void myfunc(int idx)

/* Function definition */

{

extern int globalvar; /* external variable declaration */ ...

}

Note. Each source file (i.e., a file with filename su xed by .c) is compiled to form an object module. These are later combined by the linker to form a complete executable program. The iden-tifiers of external variables and functions are visible to the linker, allowing them to be shared across separate object modules, and are said to have “external linkage”. The identifiers of non-external variables and functions are not visible to the linker, and so are private to a single source-file.

External variables and functions have static extent. This means that they are allocated memory and exist before the program starts—before the execution of main()—and continue to exist until the program terminates. External variables that are not initialised explicitly are given the default value of zero; (this is di erent to local variables, which have arbitrary initial values by default). The value of an external variable is retained from one function call to the next.

External variables are sometimes used as a convenient mechanism for avoiding long argument lists. They provide logic functions and return values options for data communication between functions. They may also permit more natural semantics if two functions operate on the same data, but neither calls the other.

2 External variables are often also called “global” variables.


The following example (from [KR88, page 79]) shows a situation where global variables might be convenient. Suppose you wish to get input from the keyboard one character at a time; the standard function getchar() provides this service. However, suppose you read in some characters and decide you are not yet ready to process them, and wish to push them back onto the input stream for a later time. This cannot be done directly, but can be simulated by storing the pushed-back characters in a bu er, and writing two functions that get and unget the characters, respectively.

#define BUFSIZE 100

char buffer[BUFSIZE]; /* buffer for pushed-back characters */ int bufidx = 0; /* buffer index */

int getch(void)

/* Get a character from stdin. */

{

if (bufidx > 0) /* get pushed-back data first */ return buffer[--bufidx];

return getchar();

}

int ungetch(int c)

/* Simulate pushing a character back onto input stream */

{

if (bufidx >= BUFSIZE) return -1; /* error: buffer full */

buffer[bufidx++] = c;

return 0;

}

The problem with the external variable is that they expose the function internally, which can lead to strong reliance between actions. Two functions are said to be “tightly coupled” if changes made to one function forces changes on the other. This style of code violates the modular design principle of decoupled functions accessible only via well-defined interfaces. A further problem with external variables is that, since their scope is over the entire multi-file program, it is easy to write code where the same identifier is used to define two di erent external variables. Overuse of external variables is said to “clutter the global name-space”, and naming conflicts can arise a ecting both functions and variables, as shown in the following example.

File one.c:

extern double myvariable;

float myname;

void myfunc(int idx);

File two.c:

extern int myvariable;

char myname(int c);

int myfunc(int idx);

As a rule, external variables are easy to overuse and should be avoided where possible.

Share:

No comments:

Post a Comment

Follow On YouTube