Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

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

88%
+13 −0
Q&A What does the static keyword do in C?

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...

posted 3y ago by Lundin‭  ·  edited 6mo ago by Lundin‭

Answer
#7: Post edited by user avatar Lundin‭ · 2024-05-21T09:34:43Z (6 months ago)
  • **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 by user avatar Lundin‭ · 2023-05-24T09:46:55Z (over 1 year ago)
  • **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 by user avatar Lundin‭ · 2021-12-02T10:49:33Z (almost 3 years ago)
  • **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 by user avatar Lundin‭ · 2021-12-02T10:47:56Z (almost 3 years ago)
  • **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 by user avatar Lundin‭ · 2021-12-02T10:43:29Z (almost 3 years ago)
  • **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 by user avatar Lundin‭ · 2021-12-02T10:42:47Z (almost 3 years ago)
  • **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 by user avatar Lundin‭ · 2021-12-02T10:40:31Z (almost 3 years ago)
**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]