Search code examples
cfunctionscopestatic

C: Static variable depending on function invocation location


Is there a way to have a static variable in a C program that not only "remembers" its last value, but also its last function invocation location, and keeps a different value for each invocation location?

I mean that when the function is invoked on multiple occasions in the main function, each invocation creates its own "instance" of the static variable, and it is treated seperatly from the other "instances".

So for example if I have this code:

#include <stdio.h>

void foo(int increment)
{
    static int sa = 10;

    sa += increment;

    printf("increment = %d, sa = %d\n", increment, sa);
}


int main()
{
    int i;

    for (i = 0; i < 5; ++i) {
        foo(1);
        foo(2);
    }
}

The output will be

increment = 1, sa = 11
increment = 2, sa = 13
increment = 1, sa = 14
increment = 2, sa = 16
increment = 1, sa = 17
increment = 2, sa = 19
increment = 1, sa = 20
increment = 2, sa = 22
increment = 1, sa = 23
increment = 2, sa = 25

However, my desired output would be

increment = 1, sa = 11
increment = 2, sa = 12
increment = 1, sa = 12
increment = 2, sa = 14
increment = 1, sa = 13
increment = 2, sa = 16
increment = 1, sa = 14
increment = 2, sa = 18
increment = 1, sa = 15
increment = 2, sa = 20

In other words, I would like to have two "instances" of sa. One of them is incremented by 1 and the other one is incremented by 2 for every main loop iteration.

If this is not possible, I guess I will have to pass the incremented value from main() to foo() and back every time (or just increment it in main()). Or is there a 3rd way to do it?

Note that I would like to have a solution that works for any number of different function invocation locations.

Edit: Removed mismatch between for-loop iteration count and output line count.


Solution

  • If you need an arbitrary number of counters, a macro can be used to create individual and completely separate counters that will do exactly as you want:

    #define FOO( increment ) \
    do \
    { \
        int localIncrement = ( increment ); \
        static int sa = 10; \
        sa += localIncrement; \
        printf("increment = %d, sa = %d\n", localIncrement, sa); \
    } \
    while ( 0 )
    

    Every invocation would create a separate counter at that point in the code. And _Generic could be used check the type of increment and improve robustness.

    For multithreaded code, sa could be an atomic value and an atomic increment could be used.