Namespaces
Variants
Views
Actions

Difference between revisions of "c/language/storage class specifiers"

From cppreference.com
< c‎ | language
(Clarified linkage for static keyword.)
(New example exhibits how different storage durations interact.)
Line 41: Line 41:
  
 
===Example===
 
===Example===
 +
Scope, Visibility, Lifetime:
 +
A variable with automatic storage duration is allocated with a high memory address. A variable with static storage duration is allocated with a low memory address; uninitialized variables are separated from initialized variables in memory for a fast internal initialization to zero. A variable with allocated storage duration is allocated memory above variables with static storage duration.
 +
{{example
 +
| code=
 +
#include <stdio.h>
 +
#include <stdlib.h>
  
{{todo}}
+
// Scope level:  0  (global area)
 +
int A;              // uninitialized global variable; this system initializes with zero
 +
int B        = 9;  // initialized global variable; stored in static (data) area
 +
static int C = 8;  // initialized static variable; stored in static (data) area
 +
int D;              // uninitialized global variable; this system initializes with zero
 +
 
 +
int main()
 +
{
 +
    // Scope level:  1
 +
    printf("Enter scope level 1:\n");
 +
    printf("====================\n");
 +
    printf("A in scope level 0 = %d\n", A);
 +
    printf("B in scope level 0 = %d\n", B);
 +
    printf("C in scope level 0 = %d\n", C);
 +
    printf("D in scope level 0 = %d\n", D);
 +
    printf("&A = %p\n", (void*)&A);
 +
    printf("&D = %p\n", (void*)&D);
 +
    printf("&B = %p\n", (void*)&B);
 +
    printf("&C = %p\n", (void*)&C);
 +
    printf("\n");
 +
 
 +
    int A = 1;  // hides global A (SL 0)
 +
    int C = 1;  // hides static C (SL 0)
 +
    printf("A in scope level 1 = %d\n", A );
 +
    printf("C in scope level 1 = %d\n", C);
 +
    printf("B in scope level 0 = %d\n", B);  // global B still visible
 +
    printf("&C = %p\n", (void*)&C);
 +
    printf("&A = %p\n", (void*)&A);
 +
    printf("\n");
 +
    int *ptr_1 = NULL;  // define here, but assign a value to it in scope level 2
 +
 
 +
    { // Scope level:  2
 +
      printf("Enter scope level 2:\n");
 +
      printf("====================\n");
 +
      int A = 2;          // hides global A (SL 0) and local A (SL 1)
 +
      int B = 2;          // hides global B (SL 0)
 +
      static int C = 2;  // hides global C (SL 0) and local C (SL 1)
 +
      printf("A in scope level 2 = %d\n", A);
 +
      printf("B in scope level 2 = %d\n", B);
 +
      printf("C in scope level 2 = %d\n", C);
 +
      printf("address of A      = %p\n", (void*)&A);
 +
      printf("address of B      = %p\n", (void*)&B);
 +
      printf("address of C      = %p\n", (void*)&C);
 +
 
 +
      // Global A is in scope but not visible.
 +
      // Local A (SL 1) is in scope but not visible.
 +
      // Local A (SL 2) is in scope and visible.
 +
      // Global B is in scope but not visible.
 +
      // Local B (SL 2) is in scope and visible.
 +
      // Static C (SL 2) is in scope, visible, and different from static C (SL 0).
 +
      // Exiting a scope level terminates the lifetime of a variable defined in that
 +
      // scope.
 +
 
 +
      int *ptr_2 = (int*)malloc(sizeof(int));  // start allocated storage duration
 +
      *ptr_2 = 2;
 +
      printf("address of allocated storage = %p\n", (void*)ptr_2);
 +
      printf("value in allocated storage  = %d\n", *ptr_2);
 +
      ptr_1 = ptr_2;  // assign to a pointer originally defined in scope level 1
 +
 
 +
      // Here, both pointers point to the same instance in allocated memory - alias.
 +
      // Leaving scope level 2 causes ptr_2 to go out of scope, and it is no longer
 +
      // available. Since the allocated instance stays around until invoking free(),
 +
      // ptr_1 will continue to point to a valid int instance when flow leaves scope
 +
      // level 2 and returns to scope level 1.  Because ptr_1 was defined in scope
 +
      // level 1, it survives the termination of scope level 2.
 +
 
 +
      printf("Exit scope level 2.\n");
 +
      printf("\n");
 +
    } // End of scope level 2
 +
 
 +
    // Scope level 1 resumes.
 +
    printf("Return to scope level 1:\n");
 +
    printf("========================\n");
 +
    printf("A (SL 1) = %d\n", A);
 +
    printf("B (SL 0) = %d\n", B);
 +
 
 +
    printf("address of int in allocated memory = %p\n", (void*)ptr_1);
 +
    printf("value of int in allocated memory  = %d\n", *ptr_1);
 +
 
 +
    free(ptr_1);                    // stop allocated storage duration
 +
    printf("%p\n", (void*)ptr_1);    // still points to allocated storage
 +
    printf("%d\n", *ptr_1);          // deallocated storage now holds 0
 +
    //  Memory, once allocated to the int instance, is now available for another use.
 +
    ptr_1 = NULL;                    // manage the unused pointer
 +
    printf("\n");
 +
 
 +
    // Reenter scope level 2 and define another static variable named C.
 +
    // The new static C resides at a different address.  At this point, the
 +
    // static area holds three memory blocks associated with the name C:
 +
    //      one is out of scope
 +
    //      two are in scope
 +
    //      one is visible.
 +
    { // Scope level 2
 +
      printf("Reenter scope level 2:\n");
 +
      printf("====================\n");
 +
      static int C = 7;
 +
      printf("C = %d\n", C);
 +
      printf("address of C = %p\n", (void*)&C);
 +
      printf("Exit scope level 2.\n");
 +
      printf("\n");
 +
    } // End of scope level 2
 +
   
 +
    printf("Return to scope level 1:\n");
 +
    printf("========================\n");
 +
    // Static C (SL 0) is in scope but not visible.
 +
    // Local C (SL 1) is in scope and visible.
 +
    printf("C = %d\n", C);
 +
    printf("address of C = %p\n", (void*)&C);
 +
 +
    return 0;
 +
}  // End of scope level 1
 +
| p=true
 +
| output=
 +
Enter scope level 1:
 +
====================
 +
A in scope level 0 = 0
 +
B in scope level 0 = 9
 +
C in scope level 0 = 8
 +
D in scope level 0 = 0
 +
&A = 0x60128c
 +
&D = 0x601288
 +
&C = 0x60126c
 +
&B = 0x601268
 +
 
 +
A in scope level 1 = 1
 +
C in scope level 1 = 1
 +
B in scope level 0 = 9
 +
&C = 0x7fff9c678bc8
 +
&A = 0x7fff9c678bcc
 +
 
 +
Enter scope level 2:
 +
====================
 +
A in scope level 2 = 2
 +
B in scope level 2 = 2
 +
C in scope level 2 = 2
 +
address of A      = 0x7fff9c678bc4
 +
address of B      = 0x7fff9c678bc0
 +
address of C      = 0x601270
 +
address of int in allocated memory = 0x602010
 +
value of int in allocated memory  = 2
 +
Exit scope level 2.
 +
 
 +
Return to scope level 1:
 +
========================
 +
A (SL 1) = 1
 +
B (SL 0) = 9
 +
address of int in allocated memory = 0x602010
 +
value of int in allocated memory  = 2
 +
0x602010
 +
0
 +
 
 +
Reenter scope level 2:
 +
======================
 +
C = 7
 +
address of C = 0x601274
 +
Exit scope level 2.
 +
 
 +
Return to scope level 1:
 +
========================
 +
C = 1
 +
address of C = 0x7fff9c678bc8
 +
}}
  
 
[[de:c/language/storage class specifiers]]
 
[[de:c/language/storage class specifiers]]

Revision as of 14:15, 8 March 2014

  • auto - automatic duration with no linkage.
  • register - automatic duration with no linkage. Also hints to the compiler to place the variable in the processor's register.
  • static - static duration with internal linkage at file scope and no linkage at block scope.
  • extern - static duration with either internal or more usually external linkage.
  • _Thread_local - (since C11) - thread storage duration.

Contents

Explanation

Storage duration

All variables in a program have one of the following storage durations that determines its lifetime:

  • automatic storage duration. The variable is allocated at the beginning of the enclosing code block and deallocated at the end. This is the default for all variables, except those declared static, extern or _Thread_local.
  • static storage duration. The variable is allocated when the program begins and deallocated when the program ends. Only one instance of the variable can exist. Variables declared with static or extern have this storage duration.
  • thread storage duration (since C11). The variable is allocated when the thread begins and deallocated when the thread ends. Each thread has its own instance of the variable. Only variables declared _Thread_local have this storage duration. _Thread_local can only be declared for variables declared with static or extern and cannot be used in a function declaration.
  • allocated storage duration. The variable is allocated and deallocated per request by using dynamic memory allocation functions.

Linkage

Linkage refers to the ability of a variable or function to be referred to in other scopes. If a variable or function with the same identifier is declared in several scopes, but cannot be referred to from all of them, then several instances of the variable are generated. The following linkages are recognized:

  • no linkage. The variable can be referred to only from the scope it is in (block scope). All variables with automatic, thread and dynamic storage durations have this linkage, as well as variables declared static at block scope.
  • internal linkage. The variable can be referred to from all scopes in the current translation unit. All variables which are declared at file scope have this linkage, including variables declared static at file scope.
  • external linkage. The variable can be referred to from any other translation units in the entire program. All variables which are declared either extern or const with no explicit storage-class specifier, but not static, have this linkage.

Keywords

auto, register, static, extern, _Thread_local

Example

Scope, Visibility, Lifetime: A variable with automatic storage duration is allocated with a high memory address. A variable with static storage duration is allocated with a low memory address; uninitialized variables are separated from initialized variables in memory for a fast internal initialization to zero. A variable with allocated storage duration is allocated memory above variables with static storage duration.

#include <stdio.h>
#include <stdlib.h>
 
// Scope level:  0  (global area)
int A;              // uninitialized global variable; this system initializes with zero
int B        = 9;   // initialized global variable; stored in static (data) area
static int C = 8;   // initialized static variable; stored in static (data) area
int D;              // uninitialized global variable; this system initializes with zero
 
int main()
{
    // Scope level:  1
    printf("Enter scope level 1:\n");
    printf("====================\n");
    printf("A in scope level 0 = %d\n", A);
    printf("B in scope level 0 = %d\n", B);
    printf("C in scope level 0 = %d\n", C);
    printf("D in scope level 0 = %d\n", D);
    printf("&A = %p\n", (void*)&A);
    printf("&D = %p\n", (void*)&D);
    printf("&B = %p\n", (void*)&B);
    printf("&C = %p\n", (void*)&C);
    printf("\n");
 
    int A = 1;   // hides global A (SL 0)
    int C = 1;   // hides static C (SL 0)
    printf("A in scope level 1 = %d\n", A );
    printf("C in scope level 1 = %d\n", C);
    printf("B in scope level 0 = %d\n", B);   // global B still visible
    printf("&C = %p\n", (void*)&C);
    printf("&A = %p\n", (void*)&A);
    printf("\n");
    int *ptr_1 = NULL;  // define here, but assign a value to it in scope level 2
 
    { // Scope level:  2
      printf("Enter scope level 2:\n");
      printf("====================\n");
      int A = 2;          // hides global A (SL 0) and local A (SL 1)
      int B = 2;          // hides global B (SL 0)
      static int C = 2;   // hides global C (SL 0) and local C (SL 1)
      printf("A in scope level 2 = %d\n", A);
      printf("B in scope level 2 = %d\n", B);
      printf("C in scope level 2 = %d\n", C);
      printf("address of A       = %p\n", (void*)&A);
      printf("address of B       = %p\n", (void*)&B);
      printf("address of C       = %p\n", (void*)&C);
 
      // Global A is in scope but not visible.
      // Local A (SL 1) is in scope but not visible.
      // Local A (SL 2) is in scope and visible.
      // Global B is in scope but not visible.
      // Local B (SL 2) is in scope and visible.
      // Static C (SL 2) is in scope, visible, and different from static C (SL 0).
      // Exiting a scope level terminates the lifetime of a variable defined in that
      // scope.
 
      int *ptr_2 = (int*)malloc(sizeof(int));   // start allocated storage duration
      *ptr_2 = 2;
      printf("address of allocated storage = %p\n", (void*)ptr_2);
      printf("value in allocated storage   = %d\n", *ptr_2);
      ptr_1 = ptr_2;  // assign to a pointer originally defined in scope level 1
 
      // Here, both pointers point to the same instance in allocated memory - alias.
      // Leaving scope level 2 causes ptr_2 to go out of scope, and it is no longer
      // available. Since the allocated instance stays around until invoking free(),
      // ptr_1 will continue to point to a valid int instance when flow leaves scope
      // level 2 and returns to scope level 1.  Because ptr_1 was defined in scope
      // level 1, it survives the termination of scope level 2.
 
      printf("Exit scope level 2.\n");
      printf("\n");
    } // End of scope level 2
 
    // Scope level 1 resumes.
    printf("Return to scope level 1:\n");
    printf("========================\n");
    printf("A (SL 1) = %d\n", A);
    printf("B (SL 0) = %d\n", B);
 
    printf("address of int in allocated memory = %p\n", (void*)ptr_1);
    printf("value of int in allocated memory   = %d\n", *ptr_1);
 
    free(ptr_1);                     // stop allocated storage duration
    printf("%p\n", (void*)ptr_1);    // still points to allocated storage
    printf("%d\n", *ptr_1);          // deallocated storage now holds 0
    //  Memory, once allocated to the int instance, is now available for another use.
    ptr_1 = NULL;                    // manage the unused pointer
    printf("\n");
 
    // Reenter scope level 2 and define another static variable named C.
    // The new static C resides at a different address.  At this point, the
    // static area holds three memory blocks associated with the name C:
    //      one is out of scope
    //      two are in scope 
    //      one is visible.
    { // Scope level 2
      printf("Reenter scope level 2:\n");
      printf("====================\n");
      static int C = 7;
      printf("C = %d\n", C);
      printf("address of C = %p\n", (void*)&C);
      printf("Exit scope level 2.\n");
      printf("\n");
    } // End of scope level 2
 
    printf("Return to scope level 1:\n");
    printf("========================\n");
    // Static C (SL 0) is in scope but not visible.
    // Local C (SL 1) is in scope and visible.
    printf("C = %d\n", C);
    printf("address of C = %p\n", (void*)&C);
 
    return 0;
}   // End of scope level 1

Possible output:

Enter scope level 1:
====================
A in scope level 0 = 0
B in scope level 0 = 9
C in scope level 0 = 8
D in scope level 0 = 0
&A = 0x60128c
&D = 0x601288
&C = 0x60126c
&B = 0x601268
 
A in scope level 1 = 1
C in scope level 1 = 1
B in scope level 0 = 9
&C = 0x7fff9c678bc8
&A = 0x7fff9c678bcc
 
Enter scope level 2:
====================
A in scope level 2 = 2
B in scope level 2 = 2
C in scope level 2 = 2
address of A       = 0x7fff9c678bc4
address of B       = 0x7fff9c678bc0
address of C       = 0x601270
address of int in allocated memory = 0x602010
value of int in allocated memory   = 2
Exit scope level 2.
 
Return to scope level 1:
========================
A (SL 1) = 1
B (SL 0) = 9
address of int in allocated memory = 0x602010
value of int in allocated memory   = 2
0x602010
0
 
Reenter scope level 2:
======================
C = 7
address of C = 0x601274
Exit scope level 2.
 
Return to scope level 1:
========================
C = 1
address of C = 0x7fff9c678bc8