Every data object has the following 7 attributes:
A declaration specifies the attributes of a list of identifiers (or names). This allows the programmer to use the declared identifiers in a source file (according to their scope). A declaration does not necessarily define (i.e. reserve memory space for) the data object that is declared. This happens when the extern keyword is used. In the following declaration:
extern int time;
The compiler is being told everything about the variable time except its address. It is up to the linker to look elsewhere to find the variable time and to fill in any instructions which refer to it.
While the declaration:
int time;
is also a definition. The difference is that it tells the compiler to allocate some space for the variable (time) being declared.
The range of values that a data item or data entity can have, depends upon the data type and data size. This depends upon the particular computer, and in some cases the particular compiler.
The Name of a data item must be declared before that data item or variable can be used in the program - otherwise, the compiler will give a fatal error because it does not know the attributes and hence does not know how to use the data. Also, it could be that a simple typing error has changed a declared variable name into something else. This lets the compiler find such errors.
A definition of a data item is where the keyword extern is not used in the declaration. Otherwise, a declaration consists of a type keyword with optional modifiers followed by comma separated list of one or more name expressions being declared. A name expression is an identifier or an identifier and some legal combination of: parenthesis, asterisks, and square brackets (for arrays), or field select, . or -> (for structures and unions). For example (ignoring the type int):
time distance[x] student.age first->next
The use of the keyword extern tells the compiler that this variable will exist somewhere and this is its type and name. The compiler knows from the type the size and what kind of operations can be performed on the data item. Later, the compiler or the linker will have to find out where in memory the data item actually is before the program is created. The scope of the variable is implied by where the data definition is encountered in the source file.
The storage class is either implicit by where in the source file the declaration occurs or is explicit in the declaration. Unless otherwise specified, a declaration outside of a function has global scope, while a declaration inside a function has local scope.
When a data declaration is a data definition the compiler will reserve or allocated memory space for the variable, or variables, being declared. It is usually not important to know where in memory the compiler (or linker) have put the variables, but it is possible to find out using the unary address of operator, &. In fact, one of the reasons for going to a high level language like 'C' is so that the programmer usually does not have to decide or be concerned about where in memory things are. This is all taken care of automatically.
Any amount of white space can exist between the tokens in a data declaration to help visually organize the information. The following examples illustrate this:
int voltage,current,power; /* for power transistor Q3 */ extern char *pname, city; float engine_temperature, exhaust_temperature; double beam_width, beam_height, beam_length;
It is strongly recommended, as good programming practice, that the actual name given to a variable be meaningful. Single letter names for variables make it easier to type the name of the data item, but make it easy to make subtle errors in large programs - especially if it has global scope.
The name should convey what information the variable contains. The extra time in typing will be frequently compensated for in avoided debugging time. Of equal or greater importance, is that the name will also make it easier for other programmers, who have to read and possibly modify your program, will know or be able to figure out what place and what use that variable serves in the program. After some months, if you have to look at your own program, you will be glad you gave meaningful names to variables (and functions). Some examples of good variable names are:
beam_length, temperature, age, WallHeight, density, Mass
In some cases, even with a longer name, it may be helpful to add a comment to the declaration (usually after the name) giving more information about the variable (see example for voltage above). Declarations are allowed to appear in only two places in a 'C' source file.
The first place is outside of the function bodies. In this case, the scope of the variable is the rest of the file. A variable declared outside of a function has a global storage class. That is it can be referenced in another file if a data declaration is used inside that other file which names that variable (and its type) with the extern storage class adjective. But, if the variable is explicitly declared with the static storage class adjective, then that variable is global only to the file in which it is declared and cannot be seen or referenced in any other file. Sometimes this is called file scope. Still, global data is implicitly or by default global only to the file it is defined in unless one explicitly uses a declaration with the "extern" keyword in another file which refers to it.
The second place that data declarations can appear is immediately after a left curly brace, {. The data declarations can follow the { only up to the first statement or the first right curly brace, }.
Data items declared in this way, are local to that block (which may be a function body or a block statement within a function). If a data item within a function appears in a data definition, that is, with the explicit extern storage class modifier, then it refers to a data item which is global either to that file or another file.
Data declarations that are local to a function (or a block within the function) have, by default, the auto or local storage class. This means that the data items so declared are on the stack. This default storage class can be overridden by explicitly using one of the two remaining storage class adjectives: static or register.
The static storage class adjective has a different meaning for local variables than global variables - and yet the meaning is not totally different. A local variable which has been declared with the static modifier, is still a local variable. The difference, is that its value is guaranteed to remain stored even after the function has been left by returning to the caller. That value is still there when the function is called again. Local static variable are not kept on the stack, but are kept with the global variables. The difference is that only the local function, or the block within that function knows about it or can reference it because it has block scope.
The register" storage class modifier, unlike the others is only a suggestion to the compiler. A suggestion that the variable be kept in a register to gain a speed advantage in its access. It is only a suggestion because there may not be enough registers to put all the local variables declared to be of register storage class into. And, in any case, the compiler can determine for itself which variables will probably give the most speed advantage if placed in registers. One restriction on register storage class variables is that the address of operator, &, cannot be used because it then has no meaning.