1

I'm learning about static variables in C and got to know that memory for static variables is allocated at compile time (how much memory has to be allocated and its virtual address is calculated during compile time and actual memory is allocated when program loads) in either data segment/.bss depending whether initialized or not

I have seen in some web site posts that since the size the object/variable will take is predefined based on the variable type, the memory is allocated at compile time. But I didn't understand the need of this in case of local static variables that are defined in a function and whose scope is only within the function.

Consider the following code snippet:

void func()
{
    static int i;
    /*some logic*/
} 

void func1()
{
    static int data[10] = {1,2,3,4,5,6,7,8,9,10};
    /*some logic*/
}

int main()
{
    /*logic not involving func() and func1()*/
}

In this case, the functions func and func1 are not at all invoked in the program, yet the memory for static variables in those functions are allocated as soon as the program loads (from what I learnt) which is actually not used. So, with this drawback what's the use of allocating memory for local static variables. Why can't the compiler allocate memory for them in the data segment when it goes through the function.

I have gone through stack overflow questions regarding this and couldn't get an exact answer Please help!!!

Richard Chambers
  • 16,643
  • 4
  • 81
  • 106
infinite loop
  • 1,309
  • 9
  • 19
  • 3
    "with this drawback" - what drawback? If the compiler had to do as you suggest, it would have to allocate the variables dynamically, which would mean they would need to be implemented as pointers. –  Jun 20 '17 at 19:17
  • In C++, local static variables aren't initialized until the declaration is executed. You can only tell the difference for objects with constructors that have side effects. – Barmar Jun 20 '17 at 19:19
  • @NeilButterworth , for static variables in functions which are not invoked, the memory getting allocated when programs loads – infinite loop Jun 20 '17 at 19:19
  • @Barmar, I think what you said may not be completely right. If the value is constant then they are intialized before, but if static variables are initialised with function args or if static variables are class or struct objects, they are initialised when executed. Observed this in MSVC++ 14.0 in x86 build – infinite loop Jun 20 '17 at 19:23
  • Allocating the memory when the function is first called would require a dynamic memory allocation -- as the memory has to persist after the function exits, allocating on the stack is not possible. A dynamic memory allocation is a very costly procedure... – DevSolar Jun 20 '17 at 19:26
  • 5
    Try compiling with optimizations and you may find that those allocations never happen. – François Andrieux Jun 20 '17 at 19:27
  • @FrançoisAndrieux , yeah an optimised code will be different. But allocating memory for static variables will be done by every compiler irrespective of optimization. What advantage it adds to do it at compile time? – infinite loop Jun 20 '17 at 19:34
  • `static` variables are **always** initialized. If you don't tell the compiler to do otherwise, to 0 – tofro Jun 20 '17 at 19:36
  • May I know the reason for downvote? I know the way it behaves, I asked why it has to be done and what advantage it adds. I couldn't find it anywhere else, so had to raise a question. – infinite loop Jun 20 '17 at 19:37
  • @infiniteloop Perhaps there is some miscommunication happening. What do you mean exactly by "allocating memory at compile time"? Second, what does it matter if the compiler decides that it will need memory for a static variable if, by the time the final binary is linked, that memory requirement is dropped? – François Andrieux Jun 20 '17 at 19:37
  • @FrançoisAndrieux , in the case/script I mentioned, even though I haven't invoked functions memory for static variables inside them is actually allocated when program loads. Isn't that a waste of memory. *I'm not optimising the code – infinite loop Jun 20 '17 at 19:43
  • 3
    *"I'm not optimising the code"* - well then of course it is going to be wasteful. That's the entire point of turning on compiler optimization, to make it get rid of as much waste (in both memory and operations) as posssible – UnholySheep Jun 20 '17 at 19:49
  • 3
    `c` or `c++`? Choose one. – KevinDTimm Jun 20 '17 at 19:51
  • 1
    @infiniteloop When people talk about optimized builds, they refer to building for Release (Visual Studio's term for it) rather than Debug. They generally do not mean to tell you to manually tune your code. – François Andrieux Jun 20 '17 at 19:53
  • Variables being initilized to zero at compile time cost you nothing. Those variables are just being put into the bss segment and if you don't use them they cost you nothing. If you use them they'll be zero filled. – Jesper Juhl Jun 20 '17 at 20:13
  • @infiniteloop If you have functions that you are not calling, that's wasteful,that code also takes up space. If those functions also contains local static variables, that's even more space taken up that's of no use. So sure, you might call that wasteful - but it's unlikely to matter one iota unless you work in a constrained environment. The compiler will optimize speed for the case when the functions are called, it's not going to try to save space for a silly case of adding functions to a program that are not called. – nos Jun 20 '17 at 21:07

1 Answers1

7

Allocating and initializing the memory at compile time means the program doesn't have to keep track of whether the function has already been entered and the variable has been initialized. Local static variables with constant initial values are treated essentially the same as global variables, except that the name is only in the scope of that function.

It's a time-space tradeoff -- initializing it during the first call would require code that has to be executed every time the function is called. Initializing it when the program is loaded means that its initialization is done as part of the block copy from the executable's text segment to the data segment of memory, along with global statics.

See What is the lifetime of a static variable in a C++ function? for the more complicated case of C++ local static variables. In C++ I would probably use a static std::array, which I don't think would be initialized until the function is entered.

If you have a large array in a function that's rarely called, and you don't want to waste memory for it, use a static pointer instead of a static array, and initialize it yourself.

void func1() {
    static int *data;

    if (!data) { // Need to protect this with a mutex if multi-threading
        data = malloc(N * sizeof(int));
        for (int i = 0; i < N; i++) {
            data[i] = i;
        }
    }
    ...
}

This is the code the compiler would have to generate to do first-time initialization of the array.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • That is what even I read, but if the functions are not even invoked what advantage it brings in allocating memory to variables that are not even used – infinite loop Jun 20 '17 at 19:25
  • 1
    The compiler runtime _does_ need to keep track of whether a local static variable has been initialised or not, so that it performs initialisation once only. In C++, it must also arrange to lock the variable against initialisation via multiple threads. –  Jun 20 '17 at 19:25
  • What if the static local variables are arrays which take a lot of memory that is unused – infinite loop Jun 20 '17 at 19:26
  • @infiniteloop - apparently they're using a compiler that doesn't remove code that isn't used, or they're using flags that turn that stuff off...or... That is an optimization that compilers are free to use or not. If it can't tell for whatever reason, or it was told not to, you're going to see all the code for those functions regardless. – Edward Strange Jun 20 '17 at 19:28
  • @infiniteloop Don't do that. Use `malloc()` along with a static pointer that you initialize the first time. – Barmar Jun 20 '17 at 19:28
  • @CrazyEddie The compiler can't tell that the function is not going to be called, so it has to generate the code in case it is. – Barmar Jun 20 '17 at 19:29
  • @Barmar , yeah I'll not do that, but if the code is not optimised and if such a case (array) is there, isn't it a waste of unused memory allocation. My query is if allocates it in the beginning, what advantage it gets. If nothing, then allocating when line of code gets executed is equally good and better? – infinite loop Jun 20 '17 at 19:32
  • Like I wrote, it's a tradeoff. The compiler assumes that most functions will be called, so it generates code that's better for that. – Barmar Jun 20 '17 at 19:33
  • 1
    Please stop repeating your question. We understand your question. Read the answers and comments you've been given. There's a tradeoff, which has been explained. – John Kugelman Jun 20 '17 at 19:34
  • @Barmar - actually it can if the code is in one complete translation unit or the linker can when you turn on whole program op. I can't think of a compiler *suite* that doesn't do it. – Edward Strange Jun 20 '17 at 19:34
  • @Barmar - in fact one of my hardest questions was created by this fact. My compiler optimized whole translation units away, which it's free to do so when linking if you never use anything in it, and so the side effects of a global init did not happen. – Edward Strange Jun 20 '17 at 19:35
  • @tofro Here guys...thinking that static variables are **always** initialized can really cause you a lot of pain: https://stackoverflow.com/questions/4383602/how-to-force-inclusion-of-unused-object-definitions-in-a-library – Edward Strange Jun 20 '17 at 19:38
  • 1
    @FrançoisAndrieux In C++ I'd probably use a class, since the constructor shouldn't be called until the first time the code is executed -- essentially what the OP wants. – Barmar Jun 20 '17 at 19:46
  • @Barmar Errata : I did not notice the C tag on this question before posting my last comment. Since the `malloc` is fixed, I'll delete the comment. – François Andrieux Jun 20 '17 at 19:48
  • Don't use `malloc` in C++, use `new`. – Jesper Juhl Jun 20 '17 at 20:19
  • @Barmar then why is it tagged "C++"? – Jesper Juhl Jun 20 '17 at 21:01
  • It's tagged both C and C++. I posted C code and an explanation that I would use a `std::array` in C++. – Barmar Jun 20 '17 at 21:02