18. DECLARATIONS
Declaration Syntax • A declaration tells the C compiler about the properties of variables and/or functions. • Declarations have the form declaration-specifiers declarators ; • Each declarator may be followed by an initializer. • Examples of declarations: static float x, y, *p; const char computer[] = "Dell laptop"; extern unsigned long int a[10], j; extern double f(double a);
Declaration Syntax • A declaration specifier is one of the following: Storage class (auto, static, extern, or register) Type specifier (for example, long, short, unsigned, int, or float) Type qualifier (const or volatile) • At most one storage class is allowed; if present, it should come first. There may be several type specifiers and/or qualifiers; these may appear in any order.
Storage Class of a Variable • The choice of storage class affects a variable’s storage duration, scope, and linkage. • The storage duration of a variable is the portion of program execution during which storage for the variable exists. Choices: Automatic — Storage for the variable is allocated when the surrounding block is executed; storage is deallocated when the block terminates, causing the variable to lose its value. Static — The variable has a permanent storage location, hence it retains its value throughout the execution of the program.
Storage Class of a Variable • The scope of a variable is the portion of the program text in which the variable can be referenced. Choices: Block scope — The variable is visible from its point of declaration to the end of the enclosing block. File scope — The variable is visible from its point of declaration to the end of the enclosing file. • The linkage of a variable determines whether it may be shared by more than one file in the same program. Choices: External — The same variable may be shared by several files. Internal — The variable is restricted to a single file. None — The variable belongs to a single function and can’t be shared at all.
Storage Class of a Variable • A variable’s default storage duration, scope, and linkage depend on where the variable is declared: Inside a block: The variable’s storage duration is automatic and it has block scope. At the outermost level of a program: The variable’s storage duration is static, it has file scope, and its linkage is external.
Variables with External Linkage • The extern class makes it possible for several source files to share the same variable. One file should contain a definition of the variable; the other files contain declarations that refer to the variable. • Suppose that the variable to be shared is named i. One of the files declares i without the word extern: int i; (If desired, an initial value for i may be supplied.) The other files contain declarations that are identical except for the presence of the word extern: extern int i; The compiler allocates storage for i only once; the other declarations of i are treated as references to the original variable i.
Variables with External Linkage • Warning: When declarations of an external variable appear in different files, the compiler cannot check that the declarations are the same. One file may contain the declaration int i; while another file contains the declaration extern long int i; An error of this kind may cause the program to behave unpredictably.
Storage Class of a Function • Function declarations (and definitions) may include a storage class; the only options are extern and static. extern indicates external linkage, allowing the function to be called from other files. static indicates internal linkage - the function may be called only within the same file. If no storage class is specified, the function is assumed to have external linkage.
Storage Class of a Function • Examples: extern int f(int i); static int g(int i); int h(int i); • Advantages of using static: Simplifies maintenance by indicating that a function is not called from outside a file. Allows functions in different files to have the same name.
Type Qualifiers • There are only two type qualifiers: const and volatile. • const is used to create “read-only” variables: const int n = 10; const int months[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; • Advantages of using const: Documents that the value of a variable will not change. The compiler will check that the program doesn’t inadvertently attempt to change the value of the object.
Declarators • In the simplest case, a declarator can be a single identifier: int i, j; • Declarators may also include a preceding *, indicating “pointer to”: int *p; • A declarator may be followed by square brackets to indicate that it represents an array: int a[10]; • A declarator may be followed by a parameter list to indicate that it represents a function: int f(int i);
Initializers A declarator that represents a variable may be followed by an initializer: int i = 0, *p = &i, a[5] = {1,2,3,4,5}; • An initializer for an array, structure, or union must contain only constant expressions, never variables or function calls: #define N 2 int powers[5] = {1, N, N*N, N*N*N, N*N*N*N}; • An initializer for a variable with static storage duration is also limited to constant expressions: #define FIRST 1 #define LAST 100 static int i = LAST - FIRST + 1;
Initializers • If a variable has automatic storage duration (and is not an array, structure, or union), its initializer can be any expression of the appropriate type—the expression need not be constant: int f(int n) { int last = n - 1; … } • What is the initial value of a variable if we don’t explicitly initialize it? Variables whose storage duration is static are initialized to 0 by default. Automatic variables have no default initial value.