Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
Post History
Storage class specifiers static is strictly speaking a storage class specifier, which is an attribute given to a variable or a function stating how it is allocated, how it is accessible and how lo...
Answer
#7: Post edited
- **Storage class specifiers**
- `static` is strictly speaking a _storage class specifier_, which is an attribute given to a variable or a function stating how it is allocated, how it is accessible and how long it will be valid. Other examples of storage class specifiers are `extern` and `register`.
- It should be noted that a storage class specifier should always be written to the far left in a declaration, doing otherwise is obsolete syntax. From C17 6.11.5: "The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature."
- The `static` keyword is however also used in a few other contexts too, which will be addressed below.
- ---
- **Scope and linkage**
- If a `static` variable or function is declared at file scope - outside any function body - it ensures that the variable or function is only accessible from that .c file and any header included by that file: from within the same _translation unit_ where it was declared.
- This is called _internal linkage_. A variable or function with internal linkage may not be referred to by other files and cannot be accessed as a "global" variable with `extern`. It is a way to give the variable private encapsulation, to reduce access and scope. It's generally considered good practice.
- In example 1), `x` is only accessible by the .c file where it was declared and not by other .c files. This reduces namespace conflicts and clutter, but more importantly also prevents other parts of the program to use the variable by accident or intentionally.
- Similarly in example 3), `func` cannot be accessed by other .c files. A function declared as `static` should be kept local to the .c file and not exposed through a header file.
- ---
- **Storage duration**
- _Storage duration_ specifies the lifetime of a variable. If declared as `static`, it has _static storage duration_. This means that the variable is valid and persists throughout the whole execution of a program.
- Variables with static storage duration have special rules of initialization. They will get initialized before `main()` is called and the program is started and not when the code line containing the declaration is encountered. Meaning that in example 1) the code `x = 5` is executed before `main()` is called. And in example 2) the code `count=0` is also executed before main() is called. This means that the initialization code is only executed once and not each time a function is entered, as would be the case with local variables.
Since the variables are initialized before `main()` is called, it also mean that the initializer list must only contain compile-time constants, since it is always resolved at compile-time. So we can't initialize a `static` variable to the result of another variable or a function call etc.- Furthermore, all variables with static storage duration are guaranteed to be initialized. These are the only variables in C with such a guarantee. If the programmer does not write initialization code explicitly, then they will get initialized to zero implicitly. (`static` pointers will get initialized as null pointers.) So in example 2) the code `count=0` is strictly speaking superfluous - the variable would have been set to zero anyway. Though it is good practice not to rely on implicit zero but to write the initializer explicitly.
- ---
- **Memory allocation**
- Variables with static storage duration also get allocated at special places in memory and not on the stack as local variables. The C standard doesn't mandate where they are allocated, but in practice all C implementations create two segments for them, normally referred to as `.data` and `.bss` (["block starting symbol"](https://en.wikipedia.org/wiki/.bss), a confusing name with lots of history behind it). This is for example standardized by the ELF file format. All static storage variables that were initialized explicitly to a non-zero value get stored in `.data`. All other static storage variables that were initialized to zero, explicitly or implicitly, get stored in `.bss`.
- Before `main()` is called, the "C run-time" start-up code executes initialization of `.data` and also sets everything in `.bss` to zero. This is the reason why they are kept as two different segments: setting a whole chunk of variables to zero in one go is faster.
- ---
- **Static inside function parameter array declarations**
- _Disclaimer: this part of the answer is an advanced topic and only included here for completeness. The vast majority of C programmers never use these features._
- With the C99 version of the C standard, various special features for declaring arrays as parameters to a function were introduced. One such feature enables us to specify that an array parameter should _at least_ have a certain size and that it cannot be a null pointer.
- In example 4) `void func (int arr[static 5]);` means that `arr` must at least have size 5 and it cannot be a null pointer.
- Historically, compilers haven't really supported this this feature until quite recently. Some modern compilers have implemented diagnostics for it. Here is an example:
- ```c
- void func (int arr[static 5])
- {}
- int main(void)
- {
- int arr[4]={1,2,3,4}; // too small array
- func(arr);
- func(NULL); // null pointer
- return 0;
- }
- ```
- For the first error, gcc 11.2 gives:
- > warning: 'func' accessing 20 bytes in a region of size 16 [-Wstringop-overflow=]
- clang 13.0.0 gives:
- > warning: array argument is too small; contains 4 elements, callee requires at least 5 [-Warray-bounds]
- For the null pointer error, we have to do `gcc -Wall` in order to get:
- > warning: argument 1 to 'int[static 20]' is null where non-null expected [-Wnonnull]
- clang 13.0.0 always gives a warning:
- > warning: null passed to a callee that requires a non-null argument [-Wnonnull]
- **Storage class specifiers**
- `static` is strictly speaking a _storage class specifier_, which is an attribute given to a variable or a function stating how it is allocated, how it is accessible and how long it will be valid. Other examples of storage class specifiers are `extern` and `register`.
- It should be noted that a storage class specifier should always be written to the far left in a declaration, doing otherwise is obsolete syntax. From C17 6.11.5: "The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature."
- The `static` keyword is however also used in a few other contexts too, which will be addressed below.
- ---
- **Scope and linkage**
- If a `static` variable or function is declared at file scope - outside any function body - it ensures that the variable or function is only accessible from that .c file and any header included by that file: from within the same _translation unit_ where it was declared.
- This is called _internal linkage_. A variable or function with internal linkage may not be referred to by other files and cannot be accessed as a "global" variable with `extern`. It is a way to give the variable private encapsulation, to reduce access and scope. It's generally considered good practice.
- In example 1), `x` is only accessible by the .c file where it was declared and not by other .c files. This reduces namespace conflicts and clutter, but more importantly also prevents other parts of the program to use the variable by accident or intentionally.
- Similarly in example 3), `func` cannot be accessed by other .c files. A function declared as `static` should be kept local to the .c file and not exposed through a header file.
- ---
- **Storage duration**
- _Storage duration_ specifies the lifetime of a variable. If declared as `static`, it has _static storage duration_. This means that the variable is valid and persists throughout the whole execution of a program.
- Variables with static storage duration have special rules of initialization. They will get initialized before `main()` is called and the program is started and not when the code line containing the declaration is encountered. Meaning that in example 1) the code `x = 5` is executed before `main()` is called. And in example 2) the code `count=0` is also executed before main() is called. This means that the initialization code is only executed once and not each time a function is entered, as would be the case with local variables.
- Since the variables are initialized before `main()` is called, it also means that the initializer list must only contain compile-time constants, since it is always resolved at compile-time. So we can't initialize a `static` variable to the result of another variable or a function call etc.
- Furthermore, all variables with static storage duration are guaranteed to be initialized. These are the only variables in C with such a guarantee. If the programmer does not write initialization code explicitly, then they will get initialized to zero implicitly. (`static` pointers will get initialized as null pointers.) So in example 2) the code `count=0` is strictly speaking superfluous - the variable would have been set to zero anyway. Though it is good practice not to rely on implicit zero but to write the initializer explicitly.
- ---
- **Memory allocation**
- Variables with static storage duration also get allocated at special places in memory and not on the stack as local variables. The C standard doesn't mandate where they are allocated, but in practice all C implementations create two segments for them, normally referred to as `.data` and `.bss` (["block starting symbol"](https://en.wikipedia.org/wiki/.bss), a confusing name with lots of history behind it). This is for example standardized by the ELF file format. All static storage variables that were initialized explicitly to a non-zero value get stored in `.data`. All other static storage variables that were initialized to zero, explicitly or implicitly, get stored in `.bss`.
- Before `main()` is called, the "C run-time" start-up code executes initialization of `.data` and also sets everything in `.bss` to zero. This is the reason why they are kept as two different segments: setting a whole chunk of variables to zero in one go is faster.
- ---
- **Static inside function parameter array declarations**
- _Disclaimer: this part of the answer is an advanced topic and only included here for completeness. The vast majority of C programmers never use these features._
- With the C99 version of the C standard, various special features for declaring arrays as parameters to a function were introduced. One such feature enables us to specify that an array parameter should _at least_ have a certain size and that it cannot be a null pointer.
- In example 4) `void func (int arr[static 5]);` means that `arr` must at least have size 5 and it cannot be a null pointer.
- Historically, compilers haven't really supported this this feature until quite recently. Some modern compilers have implemented diagnostics for it. Here is an example:
- ```c
- void func (int arr[static 5])
- {}
- int main(void)
- {
- int arr[4]={1,2,3,4}; // too small array
- func(arr);
- func(NULL); // null pointer
- return 0;
- }
- ```
- For the first error, gcc 11.2 gives:
- > warning: 'func' accessing 20 bytes in a region of size 16 [-Wstringop-overflow=]
- clang 13.0.0 gives:
- > warning: array argument is too small; contains 4 elements, callee requires at least 5 [-Warray-bounds]
- For the null pointer error, we have to do `gcc -Wall` in order to get:
- > warning: argument 1 to 'int[static 20]' is null where non-null expected [-Wnonnull]
- clang 13.0.0 always gives a warning:
- > warning: null passed to a callee that requires a non-null argument [-Wnonnull]
#6: Post edited
- **Storage class specifiers**
- `static` is strictly speaking a _storage class specifier_, which is an attribute given to a variable or a function stating how it is allocated, how it is accessible and how long it will be valid. Other examples of storage class specifiers are `extern` and `register`.
- It should be noted that a storage class specifier should always be written to the far left in a declaration, doing otherwise is obsolete syntax. From C17 6.11.5: "The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature."
The `static` keyword is however also used in a few other context too, which will be addressed below.- ---
- **Scope and linkage**
- If a `static` variable or function is declared at file scope - outside any function body - it ensures that the variable or function is only accessible from that .c file and any header included by that file: from within the same _translation unit_ where it was declared.
- This is called _internal linkage_. A variable or function with internal linkage may not be referred to by other files and cannot be accessed as a "global" variable with `extern`. It is a way to give the variable private encapsulation, to reduce access and scope. It's generally considered good practice.
- In example 1), `x` is only accessible by the .c file where it was declared and not by other .c files. This reduces namespace conflicts and clutter, but more importantly also prevents other parts of the program to use the variable by accident or intentionally.
- Similarly in example 3), `func` cannot be accessed by other .c files. A function declared as `static` should be kept local to the .c file and not exposed through a header file.
- ---
- **Storage duration**
- _Storage duration_ specifies the lifetime of a variable. If declared as `static`, it has _static storage duration_. This means that the variable is valid and persists throughout the whole execution of a program.
- Variables with static storage duration have special rules of initialization. They will get initialized before `main()` is called and the program is started and not when the code line containing the declaration is encountered. Meaning that in example 1) the code `x = 5` is executed before `main()` is called. And in example 2) the code `count=0` is also executed before main() is called. This means that the initialization code is only executed once and not each time a function is entered, as would be the case with local variables.
- Since the variables are initialized before `main()` is called, it also mean that the initializer list must only contain compile-time constants, since it is always resolved at compile-time. So we can't initialize a `static` variable to the result of another variable or a function call etc.
- Furthermore, all variables with static storage duration are guaranteed to be initialized. These are the only variables in C with such a guarantee. If the programmer does not write initialization code explicitly, then they will get initialized to zero implicitly. (`static` pointers will get initialized as null pointers.) So in example 2) the code `count=0` is strictly speaking superfluous - the variable would have been set to zero anyway. Though it is good practice not to rely on implicit zero but to write the initializer explicitly.
- ---
- **Memory allocation**
- Variables with static storage duration also get allocated at special places in memory and not on the stack as local variables. The C standard doesn't mandate where they are allocated, but in practice all C implementations create two segments for them, normally referred to as `.data` and `.bss` (["block starting symbol"](https://en.wikipedia.org/wiki/.bss), a confusing name with lots of history behind it). This is for example standardized by the ELF file format. All static storage variables that were initialized explicitly to a non-zero value get stored in `.data`. All other static storage variables that were initialized to zero, explicitly or implicitly, get stored in `.bss`.
- Before `main()` is called, the "C run-time" start-up code executes initialization of `.data` and also sets everything in `.bss` to zero. This is the reason why they are kept as two different segments: setting a whole chunk of variables to zero in one go is faster.
- ---
- **Static inside function parameter array declarations**
- _Disclaimer: this part of the answer is an advanced topic and only included here for completeness. The vast majority of C programmers never use these features._
- With the C99 version of the C standard, various special features for declaring arrays as parameters to a function were introduced. One such feature enables us to specify that an array parameter should _at least_ have a certain size and that it cannot be a null pointer.
- In example 4) `void func (int arr[static 5]);` means that `arr` must at least have size 5 and it cannot be a null pointer.
- Historically, compilers haven't really supported this this feature until quite recently. Some modern compilers have implemented diagnostics for it. Here is an example:
- ```c
- void func (int arr[static 5])
- {}
- int main(void)
- {
- int arr[4]={1,2,3,4}; // too small array
- func(arr);
- func(NULL); // null pointer
- return 0;
- }
- ```
- For the first error, gcc 11.2 gives:
- > warning: 'func' accessing 20 bytes in a region of size 16 [-Wstringop-overflow=]
- clang 13.0.0 gives:
- > warning: array argument is too small; contains 4 elements, callee requires at least 5 [-Warray-bounds]
- For the null pointer error, we have to do `gcc -Wall` in order to get:
- > warning: argument 1 to 'int[static 20]' is null where non-null expected [-Wnonnull]
- clang 13.0.0 always gives a warning:
- > warning: null passed to a callee that requires a non-null argument [-Wnonnull]
- **Storage class specifiers**
- `static` is strictly speaking a _storage class specifier_, which is an attribute given to a variable or a function stating how it is allocated, how it is accessible and how long it will be valid. Other examples of storage class specifiers are `extern` and `register`.
- It should be noted that a storage class specifier should always be written to the far left in a declaration, doing otherwise is obsolete syntax. From C17 6.11.5: "The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature."
- The `static` keyword is however also used in a few other contexts too, which will be addressed below.
- ---
- **Scope and linkage**
- If a `static` variable or function is declared at file scope - outside any function body - it ensures that the variable or function is only accessible from that .c file and any header included by that file: from within the same _translation unit_ where it was declared.
- This is called _internal linkage_. A variable or function with internal linkage may not be referred to by other files and cannot be accessed as a "global" variable with `extern`. It is a way to give the variable private encapsulation, to reduce access and scope. It's generally considered good practice.
- In example 1), `x` is only accessible by the .c file where it was declared and not by other .c files. This reduces namespace conflicts and clutter, but more importantly also prevents other parts of the program to use the variable by accident or intentionally.
- Similarly in example 3), `func` cannot be accessed by other .c files. A function declared as `static` should be kept local to the .c file and not exposed through a header file.
- ---
- **Storage duration**
- _Storage duration_ specifies the lifetime of a variable. If declared as `static`, it has _static storage duration_. This means that the variable is valid and persists throughout the whole execution of a program.
- Variables with static storage duration have special rules of initialization. They will get initialized before `main()` is called and the program is started and not when the code line containing the declaration is encountered. Meaning that in example 1) the code `x = 5` is executed before `main()` is called. And in example 2) the code `count=0` is also executed before main() is called. This means that the initialization code is only executed once and not each time a function is entered, as would be the case with local variables.
- Since the variables are initialized before `main()` is called, it also mean that the initializer list must only contain compile-time constants, since it is always resolved at compile-time. So we can't initialize a `static` variable to the result of another variable or a function call etc.
- Furthermore, all variables with static storage duration are guaranteed to be initialized. These are the only variables in C with such a guarantee. If the programmer does not write initialization code explicitly, then they will get initialized to zero implicitly. (`static` pointers will get initialized as null pointers.) So in example 2) the code `count=0` is strictly speaking superfluous - the variable would have been set to zero anyway. Though it is good practice not to rely on implicit zero but to write the initializer explicitly.
- ---
- **Memory allocation**
- Variables with static storage duration also get allocated at special places in memory and not on the stack as local variables. The C standard doesn't mandate where they are allocated, but in practice all C implementations create two segments for them, normally referred to as `.data` and `.bss` (["block starting symbol"](https://en.wikipedia.org/wiki/.bss), a confusing name with lots of history behind it). This is for example standardized by the ELF file format. All static storage variables that were initialized explicitly to a non-zero value get stored in `.data`. All other static storage variables that were initialized to zero, explicitly or implicitly, get stored in `.bss`.
- Before `main()` is called, the "C run-time" start-up code executes initialization of `.data` and also sets everything in `.bss` to zero. This is the reason why they are kept as two different segments: setting a whole chunk of variables to zero in one go is faster.
- ---
- **Static inside function parameter array declarations**
- _Disclaimer: this part of the answer is an advanced topic and only included here for completeness. The vast majority of C programmers never use these features._
- With the C99 version of the C standard, various special features for declaring arrays as parameters to a function were introduced. One such feature enables us to specify that an array parameter should _at least_ have a certain size and that it cannot be a null pointer.
- In example 4) `void func (int arr[static 5]);` means that `arr` must at least have size 5 and it cannot be a null pointer.
- Historically, compilers haven't really supported this this feature until quite recently. Some modern compilers have implemented diagnostics for it. Here is an example:
- ```c
- void func (int arr[static 5])
- {}
- int main(void)
- {
- int arr[4]={1,2,3,4}; // too small array
- func(arr);
- func(NULL); // null pointer
- return 0;
- }
- ```
- For the first error, gcc 11.2 gives:
- > warning: 'func' accessing 20 bytes in a region of size 16 [-Wstringop-overflow=]
- clang 13.0.0 gives:
- > warning: array argument is too small; contains 4 elements, callee requires at least 5 [-Warray-bounds]
- For the null pointer error, we have to do `gcc -Wall` in order to get:
- > warning: argument 1 to 'int[static 20]' is null where non-null expected [-Wnonnull]
- clang 13.0.0 always gives a warning:
- > warning: null passed to a callee that requires a non-null argument [-Wnonnull]
#5: Post edited
- **Storage class specifiers**
- `static` is strictly speaking a _storage class specifier_, which is an attribute given to a variable or a function stating how it is allocated, how it is accessible and how long it will be valid. Other examples of storage class specifiers are `extern` and `register`.
- It should be noted that a storage class specifier should always be written to the far left in a declaration, doing otherwise is obsolete syntax. From C17 6.11.5: "The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature."
- The `static` keyword is however also used in a few other context too, which will be addressed below.
- ---
- **Scope and linkage**
- If a `static` variable or function is declared at file scope - outside any function body - it ensures that the variable or function is only accessible from that .c file and any header included by that file: from within the same _translation unit_ where it was declared.
- This is called _internal linkage_. A variable or function with internal linkage may not be referred to by other files and cannot be accessed as a "global" variable with `extern`. It is a way to give the variable private encapsulation, to reduce access and scope. It's generally considered good practice.
- In example 1), `x` is only accessible by the .c file where it was declared and not by other .c files. This reduces namespace conflicts and clutter, but more importantly also prevents other parts of the program to use the variable by accident or intentionally.
- Similarly in example 3), `func` cannot be accessed by other .c files. A function declared as `static` should be kept local to the .c file and not exposed through a header file.
- ---
- **Storage duration**
- _Storage duration_ specifies the lifetime of a variable. If declared as `static`, it has _static storage duration_. This means that the variable is valid and persists throughout the whole execution of a program.
- Variables with static storage duration have special rules of initialization. They will get initialized before `main()` is called and the program is started and not when the code line containing the declaration is encountered. Meaning that in example 1) the code `x = 5` is executed before `main()` is called. And in example 2) the code `count=0` is also executed before main() is called. This means that the initialization code is only executed once and not each time a function is entered, as would be the case with local variables.
- Since the variables are initialized before `main()` is called, it also mean that the initializer list must only contain compile-time constants, since it is always resolved at compile-time. So we can't initialize a `static` variable to the result of another variable or a function call etc.
- Furthermore, all variables with static storage duration are guaranteed to be initialized. These are the only variables in C with such a guarantee. If the programmer does not write initialization code explicitly, then they will get initialized to zero implicitly. (`static` pointers will get initialized as null pointers.) So in example 2) the code `count=0` is strictly speaking superfluous - the variable would have been set to zero anyway. Though it is good practice not to rely on implicit zero but to write the initializer explicitly.
- ---
- **Memory allocation**
Variables with static storage duration also get allocated at special places in memory and not on the stack as local variables. The C standard doesn't mandate where they are allocated, but in practice all C implementations create two segments for them, normally referred to as `.data` and `.bss` (["block starting symbol"](https://en.wikipedia.org/wiki/.bss)). This is for example standardized by the ELF file format. All static storage variables that were initialized explicitly to a non-zero value get stored in `.data`. All other static storage variables that were initialized to zero, explicitly or implicitly, get stored in `.bss`.- Before `main()` is called, the "C run-time" start-up code executes initialization of `.data` and also sets everything in `.bss` to zero. This is the reason why they are kept as two different segments: setting a whole chunk of variables to zero in one go is faster.
- ---
- **Static inside function parameter array declarations**
- _Disclaimer: this part of the answer is an advanced topic and only included here for completeness. The vast majority of C programmers never use these features._
- With the C99 version of the C standard, various special features for declaring arrays as parameters to a function were introduced. One such feature enables us to specify that an array parameter should _at least_ have a certain size and that it cannot be a null pointer.
- In example 4) `void func (int arr[static 5]);` means that `arr` must at least have size 5 and it cannot be a null pointer.
- Historically, compilers haven't really supported this this feature until quite recently. Some modern compilers have implemented diagnostics for it. Here is an example:
- ```c
- void func (int arr[static 5])
- {}
- int main(void)
- {
- int arr[4]={1,2,3,4}; // too small array
- func(arr);
- func(NULL); // null pointer
- return 0;
- }
- ```
- For the first error, gcc 11.2 gives:
- > warning: 'func' accessing 20 bytes in a region of size 16 [-Wstringop-overflow=]
- clang 13.0.0 gives:
- > warning: array argument is too small; contains 4 elements, callee requires at least 5 [-Warray-bounds]
- For the null pointer error, we have to do `gcc -Wall` in order to get:
- > warning: argument 1 to 'int[static 20]' is null where non-null expected [-Wnonnull]
- clang 13.0.0 always gives a warning:
- > warning: null passed to a callee that requires a non-null argument [-Wnonnull]
- **Storage class specifiers**
- `static` is strictly speaking a _storage class specifier_, which is an attribute given to a variable or a function stating how it is allocated, how it is accessible and how long it will be valid. Other examples of storage class specifiers are `extern` and `register`.
- It should be noted that a storage class specifier should always be written to the far left in a declaration, doing otherwise is obsolete syntax. From C17 6.11.5: "The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature."
- The `static` keyword is however also used in a few other context too, which will be addressed below.
- ---
- **Scope and linkage**
- If a `static` variable or function is declared at file scope - outside any function body - it ensures that the variable or function is only accessible from that .c file and any header included by that file: from within the same _translation unit_ where it was declared.
- This is called _internal linkage_. A variable or function with internal linkage may not be referred to by other files and cannot be accessed as a "global" variable with `extern`. It is a way to give the variable private encapsulation, to reduce access and scope. It's generally considered good practice.
- In example 1), `x` is only accessible by the .c file where it was declared and not by other .c files. This reduces namespace conflicts and clutter, but more importantly also prevents other parts of the program to use the variable by accident or intentionally.
- Similarly in example 3), `func` cannot be accessed by other .c files. A function declared as `static` should be kept local to the .c file and not exposed through a header file.
- ---
- **Storage duration**
- _Storage duration_ specifies the lifetime of a variable. If declared as `static`, it has _static storage duration_. This means that the variable is valid and persists throughout the whole execution of a program.
- Variables with static storage duration have special rules of initialization. They will get initialized before `main()` is called and the program is started and not when the code line containing the declaration is encountered. Meaning that in example 1) the code `x = 5` is executed before `main()` is called. And in example 2) the code `count=0` is also executed before main() is called. This means that the initialization code is only executed once and not each time a function is entered, as would be the case with local variables.
- Since the variables are initialized before `main()` is called, it also mean that the initializer list must only contain compile-time constants, since it is always resolved at compile-time. So we can't initialize a `static` variable to the result of another variable or a function call etc.
- Furthermore, all variables with static storage duration are guaranteed to be initialized. These are the only variables in C with such a guarantee. If the programmer does not write initialization code explicitly, then they will get initialized to zero implicitly. (`static` pointers will get initialized as null pointers.) So in example 2) the code `count=0` is strictly speaking superfluous - the variable would have been set to zero anyway. Though it is good practice not to rely on implicit zero but to write the initializer explicitly.
- ---
- **Memory allocation**
- Variables with static storage duration also get allocated at special places in memory and not on the stack as local variables. The C standard doesn't mandate where they are allocated, but in practice all C implementations create two segments for them, normally referred to as `.data` and `.bss` (["block starting symbol"](https://en.wikipedia.org/wiki/.bss), a confusing name with lots of history behind it). This is for example standardized by the ELF file format. All static storage variables that were initialized explicitly to a non-zero value get stored in `.data`. All other static storage variables that were initialized to zero, explicitly or implicitly, get stored in `.bss`.
- Before `main()` is called, the "C run-time" start-up code executes initialization of `.data` and also sets everything in `.bss` to zero. This is the reason why they are kept as two different segments: setting a whole chunk of variables to zero in one go is faster.
- ---
- **Static inside function parameter array declarations**
- _Disclaimer: this part of the answer is an advanced topic and only included here for completeness. The vast majority of C programmers never use these features._
- With the C99 version of the C standard, various special features for declaring arrays as parameters to a function were introduced. One such feature enables us to specify that an array parameter should _at least_ have a certain size and that it cannot be a null pointer.
- In example 4) `void func (int arr[static 5]);` means that `arr` must at least have size 5 and it cannot be a null pointer.
- Historically, compilers haven't really supported this this feature until quite recently. Some modern compilers have implemented diagnostics for it. Here is an example:
- ```c
- void func (int arr[static 5])
- {}
- int main(void)
- {
- int arr[4]={1,2,3,4}; // too small array
- func(arr);
- func(NULL); // null pointer
- return 0;
- }
- ```
- For the first error, gcc 11.2 gives:
- > warning: 'func' accessing 20 bytes in a region of size 16 [-Wstringop-overflow=]
- clang 13.0.0 gives:
- > warning: array argument is too small; contains 4 elements, callee requires at least 5 [-Warray-bounds]
- For the null pointer error, we have to do `gcc -Wall` in order to get:
- > warning: argument 1 to 'int[static 20]' is null where non-null expected [-Wnonnull]
- clang 13.0.0 always gives a warning:
- > warning: null passed to a callee that requires a non-null argument [-Wnonnull]
#4: Post edited
- **Storage class specifiers**
- `static` is strictly speaking a _storage class specifier_, which is an attribute given to a variable or a function stating how it is allocated, how it is accessible and how long it will be valid. Other examples of storage class specifiers are `extern` and `register`.
- It should be noted that a storage class specifier should always be written to the far left in a declaration, doing otherwise is obsolete syntax. From C17 6.11.5: "The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature."
- The `static` keyword is however also used in a few other context too, which will be addressed below.
- ---
- **Scope and linkage**
- If a `static` variable or function is declared at file scope - outside any function body - it ensures that the variable or function is only accessible from that .c file and any header included by that file: from within the same _translation unit_ where it was declared.
- This is called _internal linkage_. A variable or function with internal linkage may not be referred to by other files and cannot be accessed as a "global" variable with `extern`. It is a way to give the variable private encapsulation, to reduce access and scope. It's generally considered good practice.
- In example 1), `x` is only accessible by the .c file where it was declared and not by other .c files. This reduces namespace conflicts and clutter, but more importantly also prevents other parts of the program to use the variable by accident or intentionally.
- Similarly in example 3), `func` cannot be accessed by other .c files. A function declared as `static` should be kept local to the .c file and not exposed through a header file.
- ---
- **Storage duration**
- _Storage duration_ specifies the lifetime of a variable. If declared as `static`, it has _static storage duration_. This means that the variable is valid and persists throughout the whole execution of a program.
- Variables with static storage duration have special rules of initialization. They will get initialized before `main()` is called and the program is started and not when the code line containing the declaration is encountered. Meaning that in example 1) the code `x = 5` is executed before `main()` is called. And in example 2) the code `count=0` is also executed before main() is called. This means that the initialization code is only executed once and not each time a function is entered, as would be the case with local variables.
- Since the variables are initialized before `main()` is called, it also mean that the initializer list must only contain compile-time constants, since it is always resolved at compile-time. So we can't initialize a `static` variable to the result of another variable or a function call etc.
- Furthermore, all variables with static storage duration are guaranteed to be initialized. These are the only variables in C with such a guarantee. If the programmer does not write initialization code explicitly, then they will get initialized to zero implicitly. (`static` pointers will get initialized as null pointers.) So in example 2) the code `count=0` is strictly speaking superfluous - the variable would have been set to zero anyway. Though it is good practice not to rely on implicit zero but to write the initializer explicitly.
- ---
- **Memory allocation**
Variables with static storage duration also get allocated at special places in memory and not on the stack as local variables. The C standard doesn't mandate where they are allocated, but in practice all C implementations create two segments for them, normally referred to as `.data` and `.bss` (["Basic Service Set"](https://en.wikipedia.org/wiki/.bss)). This is for example standardized by the ELF file format. All static storage variables that were initialized explicitly to a non-zero value get stored in `.data`. All other static storage variables that were initialized to zero, explicitly or implicitly, get stored in `.bss`.- Before `main()` is called, the "C run-time" start-up code executes initialization of `.data` and also sets everything in `.bss` to zero. This is the reason why they are kept as two different segments: setting a whole chunk of variables to zero in one go is faster.
- ---
- **Static inside function parameter array declarations**
- _Disclaimer: this part of the answer is an advanced topic and only included here for completeness. The vast majority of C programmers never use these features._
- With the C99 version of the C standard, various special features for declaring arrays as parameters to a function were introduced. One such feature enables us to specify that an array parameter should _at least_ have a certain size and that it cannot be a null pointer.
- In example 4) `void func (int arr[static 5]);` means that `arr` must at least have size 5 and it cannot be a null pointer.
- Historically, compilers haven't really supported this this feature until quite recently. Some modern compilers have implemented diagnostics for it. Here is an example:
- ```c
- void func (int arr[static 5])
- {}
- int main(void)
- {
- int arr[4]={1,2,3,4}; // too small array
- func(arr);
- func(NULL); // null pointer
- return 0;
- }
- ```
- For the first error, gcc 11.2 gives:
- > warning: 'func' accessing 20 bytes in a region of size 16 [-Wstringop-overflow=]
- clang 13.0.0 gives:
- > warning: array argument is too small; contains 4 elements, callee requires at least 5 [-Warray-bounds]
- For the null pointer error, we have to do `gcc -Wall` in order to get:
- > warning: argument 1 to 'int[static 20]' is null where non-null expected [-Wnonnull]
- clang 13.0.0 always gives a warning:
- > warning: null passed to a callee that requires a non-null argument [-Wnonnull]
- **Storage class specifiers**
- `static` is strictly speaking a _storage class specifier_, which is an attribute given to a variable or a function stating how it is allocated, how it is accessible and how long it will be valid. Other examples of storage class specifiers are `extern` and `register`.
- It should be noted that a storage class specifier should always be written to the far left in a declaration, doing otherwise is obsolete syntax. From C17 6.11.5: "The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature."
- The `static` keyword is however also used in a few other context too, which will be addressed below.
- ---
- **Scope and linkage**
- If a `static` variable or function is declared at file scope - outside any function body - it ensures that the variable or function is only accessible from that .c file and any header included by that file: from within the same _translation unit_ where it was declared.
- This is called _internal linkage_. A variable or function with internal linkage may not be referred to by other files and cannot be accessed as a "global" variable with `extern`. It is a way to give the variable private encapsulation, to reduce access and scope. It's generally considered good practice.
- In example 1), `x` is only accessible by the .c file where it was declared and not by other .c files. This reduces namespace conflicts and clutter, but more importantly also prevents other parts of the program to use the variable by accident or intentionally.
- Similarly in example 3), `func` cannot be accessed by other .c files. A function declared as `static` should be kept local to the .c file and not exposed through a header file.
- ---
- **Storage duration**
- _Storage duration_ specifies the lifetime of a variable. If declared as `static`, it has _static storage duration_. This means that the variable is valid and persists throughout the whole execution of a program.
- Variables with static storage duration have special rules of initialization. They will get initialized before `main()` is called and the program is started and not when the code line containing the declaration is encountered. Meaning that in example 1) the code `x = 5` is executed before `main()` is called. And in example 2) the code `count=0` is also executed before main() is called. This means that the initialization code is only executed once and not each time a function is entered, as would be the case with local variables.
- Since the variables are initialized before `main()` is called, it also mean that the initializer list must only contain compile-time constants, since it is always resolved at compile-time. So we can't initialize a `static` variable to the result of another variable or a function call etc.
- Furthermore, all variables with static storage duration are guaranteed to be initialized. These are the only variables in C with such a guarantee. If the programmer does not write initialization code explicitly, then they will get initialized to zero implicitly. (`static` pointers will get initialized as null pointers.) So in example 2) the code `count=0` is strictly speaking superfluous - the variable would have been set to zero anyway. Though it is good practice not to rely on implicit zero but to write the initializer explicitly.
- ---
- **Memory allocation**
- Variables with static storage duration also get allocated at special places in memory and not on the stack as local variables. The C standard doesn't mandate where they are allocated, but in practice all C implementations create two segments for them, normally referred to as `.data` and `.bss` (["block starting symbol"](https://en.wikipedia.org/wiki/.bss)). This is for example standardized by the ELF file format. All static storage variables that were initialized explicitly to a non-zero value get stored in `.data`. All other static storage variables that were initialized to zero, explicitly or implicitly, get stored in `.bss`.
- Before `main()` is called, the "C run-time" start-up code executes initialization of `.data` and also sets everything in `.bss` to zero. This is the reason why they are kept as two different segments: setting a whole chunk of variables to zero in one go is faster.
- ---
- **Static inside function parameter array declarations**
- _Disclaimer: this part of the answer is an advanced topic and only included here for completeness. The vast majority of C programmers never use these features._
- With the C99 version of the C standard, various special features for declaring arrays as parameters to a function were introduced. One such feature enables us to specify that an array parameter should _at least_ have a certain size and that it cannot be a null pointer.
- In example 4) `void func (int arr[static 5]);` means that `arr` must at least have size 5 and it cannot be a null pointer.
- Historically, compilers haven't really supported this this feature until quite recently. Some modern compilers have implemented diagnostics for it. Here is an example:
- ```c
- void func (int arr[static 5])
- {}
- int main(void)
- {
- int arr[4]={1,2,3,4}; // too small array
- func(arr);
- func(NULL); // null pointer
- return 0;
- }
- ```
- For the first error, gcc 11.2 gives:
- > warning: 'func' accessing 20 bytes in a region of size 16 [-Wstringop-overflow=]
- clang 13.0.0 gives:
- > warning: array argument is too small; contains 4 elements, callee requires at least 5 [-Warray-bounds]
- For the null pointer error, we have to do `gcc -Wall` in order to get:
- > warning: argument 1 to 'int[static 20]' is null where non-null expected [-Wnonnull]
- clang 13.0.0 always gives a warning:
- > warning: null passed to a callee that requires a non-null argument [-Wnonnull]
#3: Post edited
- **Storage class specifiers**
- `static` is strictly speaking a _storage class specifier_, which is an attribute given to a variable or a function stating how it is allocated, how it is accessible and how long it will be valid. Other examples of storage class specifiers are `extern` and `register`.
It should be noted that a storage class specifier should always be written to the far left of a declaration, doing otherwise is obsolete syntax. From C17 6.11.5: "The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature."- The `static` keyword is however also used in a few other context too, which will be addressed below.
- ---
- **Scope and linkage**
- If a `static` variable or function is declared at file scope - outside any function body - it ensures that the variable or function is only accessible from that .c file and any header included by that file: from within the same _translation unit_ where it was declared.
- This is called _internal linkage_. A variable or function with internal linkage may not be referred to by other files and cannot be accessed as a "global" variable with `extern`. It is a way to give the variable private encapsulation, to reduce access and scope. It's generally considered good practice.
- In example 1), `x` is only accessible by the .c file where it was declared and not by other .c files. This reduces namespace conflicts and clutter, but more importantly also prevents other parts of the program to use the variable by accident or intentionally.
- Similarly in example 3), `func` cannot be accessed by other .c files. A function declared as `static` should be kept local to the .c file and not exposed through a header file.
- ---
- **Storage duration**
- _Storage duration_ specifies the lifetime of a variable. If declared as `static`, it has _static storage duration_. This means that the variable is valid and persists throughout the whole execution of a program.
- Variables with static storage duration have special rules of initialization. They will get initialized before `main()` is called and the program is started and not when the code line containing the declaration is encountered. Meaning that in example 1) the code `x = 5` is executed before `main()` is called. And in example 2) the code `count=0` is also executed before main() is called. This means that the initialization code is only executed once and not each time a function is entered, as would be the case with local variables.
- Since the variables are initialized before `main()` is called, it also mean that the initializer list must only contain compile-time constants, since it is always resolved at compile-time. So we can't initialize a `static` variable to the result of another variable or a function call etc.
- Furthermore, all variables with static storage duration are guaranteed to be initialized. These are the only variables in C with such a guarantee. If the programmer does not write initialization code explicitly, then they will get initialized to zero implicitly. (`static` pointers will get initialized as null pointers.) So in example 2) the code `count=0` is strictly speaking superfluous - the variable would have been set to zero anyway. Though it is good practice not to rely on implicit zero but to write the initializer explicitly.
- ---
- **Memory allocation**
- Variables with static storage duration also get allocated at special places in memory and not on the stack as local variables. The C standard doesn't mandate where they are allocated, but in practice all C implementations create two segments for them, normally referred to as `.data` and `.bss` (["Basic Service Set"](https://en.wikipedia.org/wiki/.bss)). This is for example standardized by the ELF file format. All static storage variables that were initialized explicitly to a non-zero value get stored in `.data`. All other static storage variables that were initialized to zero, explicitly or implicitly, get stored in `.bss`.
- Before `main()` is called, the "C run-time" start-up code executes initialization of `.data` and also sets everything in `.bss` to zero. This is the reason why they are kept as two different segments: setting a whole chunk of variables to zero in one go is faster.
- ---
- **Static inside function parameter array declarations**
- _Disclaimer: this part of the answer is an advanced topic and only included here for completeness. The vast majority of C programmers never use these features._
- With the C99 version of the C standard, various special features for declaring arrays as parameters to a function were introduced. One such feature enables us to specify that an array parameter should _at least_ have a certain size and that it cannot be a null pointer.
- In example 4) `void func (int arr[static 5]);` means that `arr` must at least have size 5 and it cannot be a null pointer.
- Historically, compilers haven't really supported this this feature until quite recently. Some modern compilers have implemented diagnostics for it. Here is an example:
- ```c
- void func (int arr[static 5])
- {}
- int main(void)
- {
- int arr[4]={1,2,3,4}; // too small array
- func(arr);
- func(NULL); // null pointer
- return 0;
- }
- ```
- For the first error, gcc 11.2 gives:
- > warning: 'func' accessing 20 bytes in a region of size 16 [-Wstringop-overflow=]
- clang 13.0.0 gives:
- > warning: array argument is too small; contains 4 elements, callee requires at least 5 [-Warray-bounds]
- For the null pointer error, we have to do `gcc -Wall` in order to get:
- > warning: argument 1 to 'int[static 20]' is null where non-null expected [-Wnonnull]
- clang 13.0.0 always gives a warning:
- > warning: null passed to a callee that requires a non-null argument [-Wnonnull]
- **Storage class specifiers**
- `static` is strictly speaking a _storage class specifier_, which is an attribute given to a variable or a function stating how it is allocated, how it is accessible and how long it will be valid. Other examples of storage class specifiers are `extern` and `register`.
- It should be noted that a storage class specifier should always be written to the far left in a declaration, doing otherwise is obsolete syntax. From C17 6.11.5: "The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature."
- The `static` keyword is however also used in a few other context too, which will be addressed below.
- ---
- **Scope and linkage**
- If a `static` variable or function is declared at file scope - outside any function body - it ensures that the variable or function is only accessible from that .c file and any header included by that file: from within the same _translation unit_ where it was declared.
- This is called _internal linkage_. A variable or function with internal linkage may not be referred to by other files and cannot be accessed as a "global" variable with `extern`. It is a way to give the variable private encapsulation, to reduce access and scope. It's generally considered good practice.
- In example 1), `x` is only accessible by the .c file where it was declared and not by other .c files. This reduces namespace conflicts and clutter, but more importantly also prevents other parts of the program to use the variable by accident or intentionally.
- Similarly in example 3), `func` cannot be accessed by other .c files. A function declared as `static` should be kept local to the .c file and not exposed through a header file.
- ---
- **Storage duration**
- _Storage duration_ specifies the lifetime of a variable. If declared as `static`, it has _static storage duration_. This means that the variable is valid and persists throughout the whole execution of a program.
- Variables with static storage duration have special rules of initialization. They will get initialized before `main()` is called and the program is started and not when the code line containing the declaration is encountered. Meaning that in example 1) the code `x = 5` is executed before `main()` is called. And in example 2) the code `count=0` is also executed before main() is called. This means that the initialization code is only executed once and not each time a function is entered, as would be the case with local variables.
- Since the variables are initialized before `main()` is called, it also mean that the initializer list must only contain compile-time constants, since it is always resolved at compile-time. So we can't initialize a `static` variable to the result of another variable or a function call etc.
- Furthermore, all variables with static storage duration are guaranteed to be initialized. These are the only variables in C with such a guarantee. If the programmer does not write initialization code explicitly, then they will get initialized to zero implicitly. (`static` pointers will get initialized as null pointers.) So in example 2) the code `count=0` is strictly speaking superfluous - the variable would have been set to zero anyway. Though it is good practice not to rely on implicit zero but to write the initializer explicitly.
- ---
- **Memory allocation**
- Variables with static storage duration also get allocated at special places in memory and not on the stack as local variables. The C standard doesn't mandate where they are allocated, but in practice all C implementations create two segments for them, normally referred to as `.data` and `.bss` (["Basic Service Set"](https://en.wikipedia.org/wiki/.bss)). This is for example standardized by the ELF file format. All static storage variables that were initialized explicitly to a non-zero value get stored in `.data`. All other static storage variables that were initialized to zero, explicitly or implicitly, get stored in `.bss`.
- Before `main()` is called, the "C run-time" start-up code executes initialization of `.data` and also sets everything in `.bss` to zero. This is the reason why they are kept as two different segments: setting a whole chunk of variables to zero in one go is faster.
- ---
- **Static inside function parameter array declarations**
- _Disclaimer: this part of the answer is an advanced topic and only included here for completeness. The vast majority of C programmers never use these features._
- With the C99 version of the C standard, various special features for declaring arrays as parameters to a function were introduced. One such feature enables us to specify that an array parameter should _at least_ have a certain size and that it cannot be a null pointer.
- In example 4) `void func (int arr[static 5]);` means that `arr` must at least have size 5 and it cannot be a null pointer.
- Historically, compilers haven't really supported this this feature until quite recently. Some modern compilers have implemented diagnostics for it. Here is an example:
- ```c
- void func (int arr[static 5])
- {}
- int main(void)
- {
- int arr[4]={1,2,3,4}; // too small array
- func(arr);
- func(NULL); // null pointer
- return 0;
- }
- ```
- For the first error, gcc 11.2 gives:
- > warning: 'func' accessing 20 bytes in a region of size 16 [-Wstringop-overflow=]
- clang 13.0.0 gives:
- > warning: array argument is too small; contains 4 elements, callee requires at least 5 [-Warray-bounds]
- For the null pointer error, we have to do `gcc -Wall` in order to get:
- > warning: argument 1 to 'int[static 20]' is null where non-null expected [-Wnonnull]
- clang 13.0.0 always gives a warning:
- > warning: null passed to a callee that requires a non-null argument [-Wnonnull]
#2: Post edited
- **Storage class specifiers**
- `static` is strictly speaking a _storage class specifier_, which is an attribute given to a variable or a function stating how it is allocated, how it is accessible and how long it will be valid. Other examples of storage class specifiers are `extern` and `register`.
- The `static` keyword is however also used in a few other context too, which will be addressed below.
- ---
- **Scope and linkage**
- If a `static` variable or function is declared at file scope - outside any function body - it ensures that the variable or function is only accessible from that .c file and any header included by that file: from within the same _translation unit_ where it was declared.
- This is called _internal linkage_. A variable or function with internal linkage may not be referred to by other files and cannot be accessed as a "global" variable with `extern`. It is a way to give the variable private encapsulation, to reduce access and scope. It's generally considered good practice.
- In example 1), `x` is only accessible by the .c file where it was declared and not by other .c files. This reduces namespace conflicts and clutter, but more importantly also prevents other parts of the program to use the variable by accident or intentionally.
- Similarly in example 3), `func` cannot be accessed by other .c files. A function declared as `static` should be kept local to the .c file and not exposed through a header file.
- ---
- **Storage duration**
- _Storage duration_ specifies the lifetime of a variable. If declared as `static`, it has _static storage duration_. This means that the variable is valid and persists throughout the whole execution of a program.
- Variables with static storage duration have special rules of initialization. They will get initialized before `main()` is called and the program is started and not when the code line containing the declaration is encountered. Meaning that in example 1) the code `x = 5` is executed before `main()` is called. And in example 2) the code `count=0` is also executed before main() is called. This means that the initialization code is only executed once and not each time a function is entered, as would be the case with local variables.
- Since the variables are initialized before `main()` is called, it also mean that the initializer list must only contain compile-time constants, since it is always resolved at compile-time. So we can't initialize a `static` variable to the result of another variable or a function call etc.
- Furthermore, all variables with static storage duration are guaranteed to be initialized. These are the only variables in C with such a guarantee. If the programmer does not write initialization code explicitly, then they will get initialized to zero implicitly. (`static` pointers will get initialized as null pointers.) So in example 2) the code `count=0` is strictly speaking superfluous - the variable would have been set to zero anyway. Though it is good practice not to rely on implicit zero but to write the initializer explicitly.
- ---
- **Memory allocation**
- Variables with static storage duration also get allocated at special places in memory and not on the stack as local variables. The C standard doesn't mandate where they are allocated, but in practice all C implementations create two segments for them, normally referred to as `.data` and `.bss` (["Basic Service Set"](https://en.wikipedia.org/wiki/.bss)). This is for example standardized by the ELF file format. All static storage variables that were initialized explicitly to a non-zero value get stored in `.data`. All other static storage variables that were initialized to zero, explicitly or implicitly, get stored in `.bss`.
- Before `main()` is called, the "C run-time" start-up code executes initialization of `.data` and also sets everything in `.bss` to zero. This is the reason why they are kept as two different segments: setting a whole chunk of variables to zero in one go is faster.
- ---
- **Static inside function parameter array declarations**
- _Disclaimer: this part of the answer is an advanced topic and only included here for completeness. The vast majority of C programmers never use these features._
- With the C99 version of the C standard, various special features for declaring arrays as parameters to a function were introduced. One such feature enables us to specify that an array parameter should _at least_ have a certain size and that it cannot be a null pointer.
- In example 4) `void func (int arr[static 5]);` means that `arr` must at least have size 5 and it cannot be a null pointer.
- Historically, compilers haven't really supported this this feature until quite recently. Some modern compilers have implemented diagnostics for it. Here is an example:
- ```c
- void func (int arr[static 5])
- {}
- int main(void)
- {
- int arr[4]={1,2,3,4}; // too small array
- func(arr);
- func(NULL); // null pointer
- return 0;
- }
- ```
- For the first error, gcc 11.2 gives:
- > warning: 'func' accessing 20 bytes in a region of size 16 [-Wstringop-overflow=]
- clang 13.0.0 gives:
- > warning: array argument is too small; contains 4 elements, callee requires at least 5 [-Warray-bounds]
- For the null pointer error, we have to do `gcc -Wall` in order to get:
- > warning: argument 1 to 'int[static 20]' is null where non-null expected [-Wnonnull]
- clang 13.0.0 always gives a warning:
- > warning: null passed to a callee that requires a non-null argument [-Wnonnull]
- **Storage class specifiers**
- `static` is strictly speaking a _storage class specifier_, which is an attribute given to a variable or a function stating how it is allocated, how it is accessible and how long it will be valid. Other examples of storage class specifiers are `extern` and `register`.
- It should be noted that a storage class specifier should always be written to the far left of a declaration, doing otherwise is obsolete syntax. From C17 6.11.5: "The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature."
- The `static` keyword is however also used in a few other context too, which will be addressed below.
- ---
- ---
- **Scope and linkage**
- If a `static` variable or function is declared at file scope - outside any function body - it ensures that the variable or function is only accessible from that .c file and any header included by that file: from within the same _translation unit_ where it was declared.
- This is called _internal linkage_. A variable or function with internal linkage may not be referred to by other files and cannot be accessed as a "global" variable with `extern`. It is a way to give the variable private encapsulation, to reduce access and scope. It's generally considered good practice.
- In example 1), `x` is only accessible by the .c file where it was declared and not by other .c files. This reduces namespace conflicts and clutter, but more importantly also prevents other parts of the program to use the variable by accident or intentionally.
- Similarly in example 3), `func` cannot be accessed by other .c files. A function declared as `static` should be kept local to the .c file and not exposed through a header file.
- ---
- **Storage duration**
- _Storage duration_ specifies the lifetime of a variable. If declared as `static`, it has _static storage duration_. This means that the variable is valid and persists throughout the whole execution of a program.
- Variables with static storage duration have special rules of initialization. They will get initialized before `main()` is called and the program is started and not when the code line containing the declaration is encountered. Meaning that in example 1) the code `x = 5` is executed before `main()` is called. And in example 2) the code `count=0` is also executed before main() is called. This means that the initialization code is only executed once and not each time a function is entered, as would be the case with local variables.
- Since the variables are initialized before `main()` is called, it also mean that the initializer list must only contain compile-time constants, since it is always resolved at compile-time. So we can't initialize a `static` variable to the result of another variable or a function call etc.
- Furthermore, all variables with static storage duration are guaranteed to be initialized. These are the only variables in C with such a guarantee. If the programmer does not write initialization code explicitly, then they will get initialized to zero implicitly. (`static` pointers will get initialized as null pointers.) So in example 2) the code `count=0` is strictly speaking superfluous - the variable would have been set to zero anyway. Though it is good practice not to rely on implicit zero but to write the initializer explicitly.
- ---
- **Memory allocation**
- Variables with static storage duration also get allocated at special places in memory and not on the stack as local variables. The C standard doesn't mandate where they are allocated, but in practice all C implementations create two segments for them, normally referred to as `.data` and `.bss` (["Basic Service Set"](https://en.wikipedia.org/wiki/.bss)). This is for example standardized by the ELF file format. All static storage variables that were initialized explicitly to a non-zero value get stored in `.data`. All other static storage variables that were initialized to zero, explicitly or implicitly, get stored in `.bss`.
- Before `main()` is called, the "C run-time" start-up code executes initialization of `.data` and also sets everything in `.bss` to zero. This is the reason why they are kept as two different segments: setting a whole chunk of variables to zero in one go is faster.
- ---
- **Static inside function parameter array declarations**
- _Disclaimer: this part of the answer is an advanced topic and only included here for completeness. The vast majority of C programmers never use these features._
- With the C99 version of the C standard, various special features for declaring arrays as parameters to a function were introduced. One such feature enables us to specify that an array parameter should _at least_ have a certain size and that it cannot be a null pointer.
- In example 4) `void func (int arr[static 5]);` means that `arr` must at least have size 5 and it cannot be a null pointer.
- Historically, compilers haven't really supported this this feature until quite recently. Some modern compilers have implemented diagnostics for it. Here is an example:
- ```c
- void func (int arr[static 5])
- {}
- int main(void)
- {
- int arr[4]={1,2,3,4}; // too small array
- func(arr);
- func(NULL); // null pointer
- return 0;
- }
- ```
- For the first error, gcc 11.2 gives:
- > warning: 'func' accessing 20 bytes in a region of size 16 [-Wstringop-overflow=]
- clang 13.0.0 gives:
- > warning: array argument is too small; contains 4 elements, callee requires at least 5 [-Warray-bounds]
- For the null pointer error, we have to do `gcc -Wall` in order to get:
- > warning: argument 1 to 'int[static 20]' is null where non-null expected [-Wnonnull]
- clang 13.0.0 always gives a warning:
- > warning: null passed to a callee that requires a non-null argument [-Wnonnull]
#1: Initial revision
**Storage class specifiers** `static` is strictly speaking a _storage class specifier_, which is an attribute given to a variable or a function stating how it is allocated, how it is accessible and how long it will be valid. Other examples of storage class specifiers are `extern` and `register`. The `static` keyword is however also used in a few other context too, which will be addressed below. -- **Scope and linkage** If a `static` variable or function is declared at file scope - outside any function body - it ensures that the variable or function is only accessible from that .c file and any header included by that file: from within the same _translation unit_ where it was declared. This is called _internal linkage_. A variable or function with internal linkage may not be referred to by other files and cannot be accessed as a "global" variable with `extern`. It is a way to give the variable private encapsulation, to reduce access and scope. It's generally considered good practice. In example 1), `x` is only accessible by the .c file where it was declared and not by other .c files. This reduces namespace conflicts and clutter, but more importantly also prevents other parts of the program to use the variable by accident or intentionally. Similarly in example 3), `func` cannot be accessed by other .c files. A function declared as `static` should be kept local to the .c file and not exposed through a header file. --- **Storage duration** _Storage duration_ specifies the lifetime of a variable. If declared as `static`, it has _static storage duration_. This means that the variable is valid and persists throughout the whole execution of a program. Variables with static storage duration have special rules of initialization. They will get initialized before `main()` is called and the program is started and not when the code line containing the declaration is encountered. Meaning that in example 1) the code `x = 5` is executed before `main()` is called. And in example 2) the code `count=0` is also executed before main() is called. This means that the initialization code is only executed once and not each time a function is entered, as would be the case with local variables. Since the variables are initialized before `main()` is called, it also mean that the initializer list must only contain compile-time constants, since it is always resolved at compile-time. So we can't initialize a `static` variable to the result of another variable or a function call etc. Furthermore, all variables with static storage duration are guaranteed to be initialized. These are the only variables in C with such a guarantee. If the programmer does not write initialization code explicitly, then they will get initialized to zero implicitly. (`static` pointers will get initialized as null pointers.) So in example 2) the code `count=0` is strictly speaking superfluous - the variable would have been set to zero anyway. Though it is good practice not to rely on implicit zero but to write the initializer explicitly. --- **Memory allocation** Variables with static storage duration also get allocated at special places in memory and not on the stack as local variables. The C standard doesn't mandate where they are allocated, but in practice all C implementations create two segments for them, normally referred to as `.data` and `.bss` (["Basic Service Set"](https://en.wikipedia.org/wiki/.bss)). This is for example standardized by the ELF file format. All static storage variables that were initialized explicitly to a non-zero value get stored in `.data`. All other static storage variables that were initialized to zero, explicitly or implicitly, get stored in `.bss`. Before `main()` is called, the "C run-time" start-up code executes initialization of `.data` and also sets everything in `.bss` to zero. This is the reason why they are kept as two different segments: setting a whole chunk of variables to zero in one go is faster. --- **Static inside function parameter array declarations** _Disclaimer: this part of the answer is an advanced topic and only included here for completeness. The vast majority of C programmers never use these features._ With the C99 version of the C standard, various special features for declaring arrays as parameters to a function were introduced. One such feature enables us to specify that an array parameter should _at least_ have a certain size and that it cannot be a null pointer. In example 4) `void func (int arr[static 5]);` means that `arr` must at least have size 5 and it cannot be a null pointer. Historically, compilers haven't really supported this this feature until quite recently. Some modern compilers have implemented diagnostics for it. Here is an example: ```c void func (int arr[static 5]) {} int main(void) { int arr[4]={1,2,3,4}; // too small array func(arr); func(NULL); // null pointer return 0; } ``` For the first error, gcc 11.2 gives: > warning: 'func' accessing 20 bytes in a region of size 16 [-Wstringop-overflow=] clang 13.0.0 gives: > warning: array argument is too small; contains 4 elements, callee requires at least 5 [-Warray-bounds] For the null pointer error, we have to do `gcc -Wall` in order to get: > warning: argument 1 to 'int[static 20]' is null where non-null expected [-Wnonnull] clang 13.0.0 always gives a warning: > warning: null passed to a callee that requires a non-null argument [-Wnonnull]