Does a static variable inside a function ever go out of scope? - c

While reading this Question I noticed an interesting scenario. The question has a function which is only called once:
int* missing_elements(int arr[], int len){
static int arr2[]={0};
for(int i=0,j=1; i < 7; i++,j++){
if(arr[i] != j){
arr2[i]=j;
if(arr[i] == j++){
break;
}
}
}
return arr2;
}
The function is returning a pointer to an array that is defined as static within the function. I'm curious about how the scope of arr2[] is handled. If arr2[] was defined as not static then then it would fall out of scope and you couldn't assume that the returned pointer would point to valid data.
My question is since arr2 is static will it always be in scope even if the function that defines it will never be called again. Is this undefined behavior or can we assume that it never loses scope?

My question is since arr2 is static will it always be in scope even if
the function that defines it will never be called again. Is this
undefined behavior or can we assume that it never loses scope?
If we look at draft N2310 - 6.2.4 Storage durations of objects
You'll see that it states (emphasis mine)
An object whose identifier is declared without the storage-class
specifier
_Thread_local, and either with external or internal linkage or with the storage-class specifier static, has static storage duration. Its
lifetime is the entire execution of the program and its stored value
is initialized only once, prior to program startup.

Related

Same memory location assignment for two static variables

I have the below code and I see that the two variables have been assigned with same address. Both the variables are completely different type . Is there anyway I can void this ? And under what circumstances does the same memory gets allocated to both the variables .
static int Sw_Type [];
static BOOL Sw_Update;
void main()
{
int i;
int bytes = 3;
if (Sw_Update!= TRUE)
{
for(i = 0; i< bytes ;i++)
{
Sw_Type [i] = *Ver_Value;
Ver_Value++;
}
Sw_Update= TRUE;
}
}
This is a snippet of my code and "Ver_Value" is a structure which gets assigned in different function.
So the problem I am seeing is , when Sw_Update gets updated, Sw_Type [1] is getting updated and I see these two have same memory address.
static int Sw_Type []; constitutes a tentative definition, per C 2018 6.9.2 2:
A declaration of an identifier for an object that has file scope without an initializer, and without a storage-class specifier or with the storage-class specifier static, constitutes a tentative definition. If a translation unit contains one or more tentative definitions for an identifier, and the translation unit contains no external definition for that identifier, then the behavior is exactly as if the translation unit contains a file scope declaration of that identifier, with the composite type as of the end of the translation unit, with an initializer equal to 0.
Since your program provides no non-tentative definition, it is as if it ended with static int Sw_Type [] = { 0 };. (In case it is not clear from the text quoted above that the result is indeed an array of one element, it is made clear by Example 2 in paragraph 5 of the same clause.)
Thus, Sw_Type is an array of one int. It contains only the element Sw_Type[0]. The behavior of accessing Sw_Type[1] is not defined by the C standard. From the observations you report, it appears as if Sw_Update follows Sw_Type in memory, and accessing Sw_Type[1] results in modifying Sw_Update. This behavior is of course not reliable.
To make Sw_Type larger, you must declare a size for it, as with static int Sw_Type[4];.
Note: 6.9.2 3 says “If the declaration of an identifier for an object is a tentative definition and has internal linkage, the declared type shall not be an incomplete type.” While this might be read as applying to the declared type in each declaration that is a tentative definition, I think it might be intended to apply to the declared type of the object once its composite type is fully resolved at the end of the translation unit. Experimentally, Clang is okay with accepting an incomplete type at first and completing it later.
So the problem I am seeing is , when Sw_Update gets updated, Sw_Type [1] is getting updated and I see these two have same memory address.
There is no Sw_Type [1]. Only an array with two or more elements has a second entry, and Sw_Type is not an array with two or more elements. Accessing an array out of bounds can certainly stomp on other objects.

What is the use of Static in declaring character arrays?

I was doing this program from Hackerrank in C and I solved the program without declaring my character array 'result' as static. It returned an error where my Output didn't match with the Expected Output. But as soon as I inserted the keyword 'static' in the declaration of the array 'result', the code ran successfully.
Here is my code snippet:
char* timeConversion(char* s)
{
int i;
static char result[100]; // this doesn't work if i remove the word 'static'
if (s[0]=='1' && s[1]=='2' && s[8]=='A')
{
result[0]='0';
result[1]='0';
for (i=2;i<8;i++)
result[i]=s[i];
}
else if (s[0]=='1' && s[1]=='2' && s[8]=='P')
for (i=0;i<8;i++)
result[i]=s[i];
else
{
if (s[8]=='A')
for (i=0;i<8;i++)
result[i]=s[i];
if (s[8]=='P')
{
result[0]=s[0]+1;
result[1]=s[1]+2;
for (i=2;i<8;i++)
result[i]=s[i];
}
}
return result;
}
I don't understand that, what is the use of Static here?
Two things:
You are returning the address of a stack-allocated array from your function. If it were not static, you'd just be returning the address of an array that doesn't exist anymore since ordinarily, objects on the stack disappear when they go out of scope (i.e. when the function returns). To return an array from a function that can actually be used by the calling code, it must either be allocated on the heap (i.e. with malloc) or be declared static, since local variables in functions that are declared with the static qualifier persist after the function returns.
If a variable without the static qualifier is declared but not initialized explicitly, it just gets whatever's already in memory at the time.
If a local variable or array is declared with the static qualifier, it is implicitly initialized with zeroes. This means that the variable result can be populated with the parsed date/time value and is guaranteed to be a null-terminated string since all the elements of the array that aren't populated by the code in the function are already zero.
C11 6.2.2 Linkages of identifiers(P3):
If the declaration of a file scope identifier for an object or a
function contains the storage class specifier static, the identifier
has internal linkage.30)
Footnote:
30) A function declaration can contain the storage-class specifier
static only if it is at file scope; see
6.7.1.
It means static variable is declared once and its life time is entire execution of the program. That's why return static array working fine in your code, which makes sense.
If you remove static keyword, then array become a local or auto and scope of local variable exists only within the block or function that it is declared in. in your code, you are trying to return local array, that's invoked undefined behaviour.
GCC Compiler warning :
In function 'timeConversion':
prog.c:30:12: warning: function returns address of local variable [-Wreturn-local-addr]
return result;
^~~~~~
I don't understand that, what is the use of Static here?
A couple of meanings of static relevant to your program, taken from C99 standard (N1256):
6.2.4 Storage durations of objects
An object has a storage duration that determines its lifetime. There are three storage
durations: static, automatic, and allocated. Allocated storage is described in 7.20.3.
The lifetime of an object is the portion of program execution during which storage is
guaranteed to be reserved for it. An object exists, has a constant address,25) and retains
its last-stored value throughout its lifetime.26) If an object is referred to outside of its lifetime, the behavior is undefined. The value of a pointer becomes indeterminate when
the object it points to reaches the end of its lifetime.
An object whose identifier is declared with external or internal linkage, or with the
storage-class specifier static has static storage duration. Its lifetime is the entire
execution of the program and its stored value is initialized only once, prior to program
startup.
6.7.8 Initialization
....
10. If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate. If an object that has static storage duration is not initialized explicitly, then:
— if it has pointer type, it is initialized to a null pointer;
— if it has arithmetic type, it is initialized to (positive or unsigned) zero;
— if it is an aggregate, every member is initialized (recursively) according to these rules;
— if it is a union, the first named member is initialized (recursively) according to these
rules.
So, in your example, static specifies the lifetime of the result array and also initializes the array as per the rules highlighted above.

Why doesn't `bar` in this code have static storage duration?

Code goes first:
#include <stdio.h>
void foo()
{
static int bar;
}
int main()
{
bar++;
return 0;
}
The compiler(Clang) complains:
static.c:10:2: error: use of undeclared identifier 'bar'
Shouldn't the statement static int bar; in foo() give bar static storage duration, which makes it declared and initialized prior to main function?
You are confusing the scope of a variable with the storage duration.
As mentioned in the C11 standard, chapter §6.2.1, Scopes of identifiers,
for file scope
[...] If the declarator or type specifier that declares the identifier
appears outside of any block or list of parameters, the identifier has file scope, which
terminates at the end of the translation unit. [...]
and for function (or block) scope
[...] If the declarator or type specifier that
declares the identifier appears inside a block or within the list of parameter declarations in
a function definition, the identifier has block scope, which terminates at the end of the
associated block. [...]
In your case, bar has the file scope in foo(). So this is not visible in main().
OTOH, for the storage duration part,
An object whose identifier is declared without the storage-class specifier
_Thread_local, and either with external or internal linkage or with the storage-class
specifier static, has static storage duration. Its lifetime is the entire execution of the
program and its stored value is initialized only once, prior to program startup.
So, to summarize, bar has static storage duration, but the scope is limited to the foo() function. So, it is
declared and initialized prior to main() function
(before main() starts, to be exact) but not visible and accessible in main().
Marking something as static within a function relocates its storage off of the stack and allows its value to persist across multiple calls.
Marking something static, however, does nothing to change the scope of the variable. While you certainly could create a pointer that is aimed at bar and manipulate it from main, the compiler will view bar as undefined within main because of scoping.

Redeclaration of static variables in C... never happens?

I'm trying to fully understand how static variables work in C. I understand that using the static keyword makes the lifetime of the variable equal to the duration of the program. The following example has one thing that confuses me though...
My static_test.c file:
#include <stdio.h>
void foo(){
static int counter = 0;
counter++;
printf("This function has been called %i times.\n",counter);
return;
}
int main(){
int i;
for(i=0;i<10;i++){
foo();
}
return 0;
}
When I first read this example it makes me wonder why the function doesn't print out 0 every time since we are assigning 0 to the static variable.
Is this because once a static variable is declared the compiler ignores another declaration of the same variable on the next calls to my foo() function?
Thanks!
Despite the use of =, this is an initialization, NOT an assignment. So it happens when the variable is initialized and not when the 'statement' is apparently 'executed'. Since it is a static variable, it is initialized once when the program starts, rather than every time the function runs.
Static variables are initialized exactly once at program start, before your function is ever called. The fact that it's a local variable doesn't affect this rule.
In addition, static storage class variables are automatically initialized to zero if not explicitly initialized; the = 0 in your program is superfluous.
From the C11 drafts standard (ISO/IEC 9899:201x), section 6.2.4 Storage durations of objects, paragraph 3:
An object whose identifier is declared … with the storage-class specifier static has static storage duration. Its lifetime is the entire execution of the program and its stored value is initialized only once, prior to program startup.
Yes, the compiler looks for an initial assignment after declaring a static variable and only executes it once, when the program starts.
This only happens when you declare the variable though. For example,
void foo(){
static int counter;
counter = 0;
counter++;
printf("This function has been called %i times.\n",counter);
return;
}
Would print 1 every time.
Static means the variable exists outside of the life time of the function. Think of it as a slightly clever global variable.

Within the same function, is it UB to access—through indirection—a local variable not in scope?

After the second closing brace, b is accessible only through indirection through a.
int main() {
int *a;
{
int b = 42;
a = &b;
}
printf("%d", *a); // UB?
return 0;
}
Since b is not anymore in scope, is this UB? I know it's UB to dereference a pointer to a non-static local variable from a function that has already returned, but in this case everything is within the same function.
This is UB in C++, but I'm not sure about C.
Yes, it's undefined behaviour to access any variable that has reached it's end of life. Scope and storage duration are subtly different here. Scope is more "when is the variable identifier visible?" and storage duration is "when does the variable itself exist?".
You can have things in scope and enduring such as:
int main (void) {
int spoon = 42;
// spoon is both in scope and enduring here
return 0;
}
Or out of scope but enduring:
int main (void) {
int *pSpoon;
{
static int spoon = 42;
pSpoon = &spoon;
}
// spoon is out of scope but enduring here (use *pSpoon to get to it)
return 0;
}
You can also have variables out of scope and not enduring, such as with:
int main (void) {
// spoon is neither in scope nor enduring here ("there is no spoon")
return 0;
}
In fact, the only thing you can't have is a variable in scope but not enduring. The identifier is tied to the the storage since it makes little sense allowing a variable with no backing storage.
I'm not talking about pointers here, that's an extra level of indirection - an in-scope pointer variable always has storage for the pointer value itself, even if the thing it points to has ended, or not yet begun, its storage duration.
The fact that undefined behaviour may work in some situations in no way makes the behaviour defined, in fact that's one of the most annoying features of undefined behaviour in that it sometimes does work. Otherwise it would be much easier to detect.
In this particular case, the b variable storage duration ends at the inner closing brace so trying to access it after that point is not wise.
The controlling part of the standard is c11 6.2.4 Storage duration of objects (slightly paraphrased to remove unnecessary bits):
An object has a storage duration that determines its lifetime. There are four storage
durations: static, thread, automatic, and allocated.
An object whose identifier is declared with no linkage and without the storage-class specifier static has automatic storage duration.
For such an object, its lifetime extends from entry into the block with which it is associated until execution of that block ends in any way.
b is still within a different, nested, scope that has exited and thus destroyed b by the time you access it. So it IS undefined behavior. Everything being within the same function is immaterial.
For the purposes of variable lifetimes, you can think of "functions that have returned" as nested scopes, or vice versa.

Resources