Clemson University -- CPSC 215 -- Summer 2003 chpt. 3 General Principles 1. The storage class of a variable has implications on its duration, scope, and linkage. 2. The three storage classes are auto, register, and static. 3. The duration (or lifetime) of a variable is the duration of the program, duration of a function or block, or programmer-defined (i.e., dynamic memory allocation). 4. The scope of a variable is either block or file. 5. The linkage of a variable is either internal or external. C variables / symbolic name | data type (optionally with qualifier) | | / allocated in data area, stack, or heap | storage class | duration (lifetime or extent) variable | | scope (visibility of the variable name) | \ linkage (may have been allocated elsewhere) | | address in memory (none if only allocated in register) | initialization (optional) \ value declaration - appears at top of function (or block), before any executable statements [note: to be more formal, a "declaration" identifies a name and type of a variable, while a "definition" both declares a variable and will lead to storage allocation for the variable] storage class - where is the variable allocated? code - program code data - global and static data heap - dynamically allocated variables stack - local data | . . . | +-------+. int g; /* g in data segment */ | code | \ |-------| | program's int main(){ | data | | layout in int a; /* a on stack */ |-------| | memory ... | heap | | int *b = malloc(...); /* b points */ |---|---| | ... /* into heap */ | . V . | | if( ... ){ | . . . | | static int c = 0; /* c in data */ | . ^ . | | ... /* segment; */ |---|---| | } /* only set */ | stack | / } /* to 0 once */ +-------+' | . . . | auto - automatic allocation on stack upon entry to function (or block) and deallocated upon exit; multiple allocations for multiple entries (i.e., recursion); if initial values are given, they will be reassigned upon each entry; this is the default storage class register similar to auto, but compilers often ignore the register keyword static - single allocation with lifetime of program; if initial values are given, they will be assigned once before the program starts scope - where is the variable visible? local variables and formal parameters have a block scope of a function's outermost block local variables can also have a more restricted block scope - i.e., inside nested { and } a declaration within an inner block hides a variable having the same name in an outer block global variables (variables declared outside a function) and function names have file scope - from that point in file on two other types of scope 1. labels have function scope (but don't use goto!) 2. variable names in prototypes must be unique but are otherwise ignored 3. static keyword is used with function names to mean "not public" linkage - where is the variable located relative to this source file? extern used with local variables - required for proper linkage used for declaration (opposed to definition) to provide addressing info w/o allocation (i.e., a name that will need to be linked to the actual memory location of a global variable that is defined elsewhere) extern used with global variables - by convention compiler sorts out global variables but convention is to use extern with all but one (i.e., one definition with multiple referencing declarations) extern assumed for function names (makes function name globally visible) unless specified as static example /* global vars - allocated duration scope linkage */ /* --------- -------- ----- ------- */ int a; /* data seg static file public */ extern int b; /* no static file from another file */ static int c; /* data seg static file private to this file */ /* function names - scope linkage */ /* ----- ------- */ void fn_1( void ){} /* file public */ void extern fn_2( void ){} /* file public */ void static fn_3( void ){} /* file private to this file */ /* parameter names - scope */ /* in prototype ----- */ void fn_4( int d, int e ); /* prototype */ /* local vars - allocated duration scope */ /* --------- -------- ----- */ void fn_5( int f ){ /* stack auto block (outermost) */ int g; /* stack auto block (outermost) */ static int h; /* data seg static block (outermost) */ register int i; /* register auto block (outermost) */ ... { int j; /* stack auto block (inner) */ extern int k; /* no static block (inner) */ ... } ... } example #include void a( void ); void b( void ); void c( void ); int x = 1; /* this x is global */ int main(){ int x = 5; /* this x is local to main */ printf( "local x in outer scope of main is %d\n", x ); { /* start new scope */ int x = 7; /* this x is local to this block */ printf( "local x in inner scope of main is %d\n", x ); } /* end new scope */ printf( "local x in outer scope of main is %d\n", x ); a(); /* a has automatic local x */ b(); /* b has static local x */ c(); /* c uses global x */ a(); /* a reinitializes automatic local x */ b(); /* static local x retains its previous value */ c(); /* global x also retains its value */ printf( "local x in main is %d\n", x ); return 0; } void a( void ){ int x = 25; /* initialized each time a is called */ printf( "\nlocal x in a is %d after entering\n", x ); x++; printf( "local x in a is %d before exiting\n", x ); } void b( void ){ static int x = 50; /* static initialization only */ /* first time b is called */ printf( "\nlocal static x is %d on entering b\n", x ); x++; printf( "local static x is %d on exiting b\n", x ); } void c( void ){ printf( "\nglobal x is %d on entering c\n", x ); x *= 10; printf( "global x is %d on exiting c\n", x ); } % a.out local x in outer scope of main is 5 local x in inner scope of main is 7 local x in outer scope of main is 5 local x in a is 25 after entering local x in a is 26 before exiting local static x is 50 on entering b local static x is 51 on exiting b global x is 1 on entering c global x is 10 on exiting c local x in a is 25 after entering local x in a is 26 before exiting local static x is 51 on entering b local static x is 52 on exiting b global x is 10 on entering c global x is 100 on exiting c local x in main is 5 file scope void a( void ); void b( void ); int main(){ a(); b(); return 0; } void a( void ){ printf( "x = %d\n", x ); } int x = 0; /* this x is global beyond this point */ void b( void ){ printf( "x = %d\n", x ); } % gcc scope.c scope.c: In function `a': scope.c:15: `x' undeclared (first use in this function) scope.c:15: (Each undeclared identifier is reported only once scope.c:15: for each function it appears in.) scope.c: At top level: scope.c:18: `x' used prior to declaration static functions are private to the source file m.c: void a(void); a.c: void a(void){ printf("in fn a\n"); } void b(void); void static b(void){ printf("in fn b\n"); } int main(){ a(); } % gcc m.c a.c % a.out in fn a m.c: void a(void); a.c: void a(void){ printf("in fn a\n"); } void b(void); void static b(void){ printf("in fn b\n"); } int main(){ b(); } % gcc m.c a.c % a.out /var/tmp//ccoB26hd.o: In function `main': /var/tmp//ccoB26hd.o(.text+0x4): undefined reference to `b' collect2: ld returned 1 exit status