Thread: What is the difference between declaring global or static local variables ?

  1. #1
    Registered User
    Join Date
    Jan 2016
    Posts
    84

    What is the difference between declaring global or static local variables ?

    Hi,

    I'm used to use global variables for some reasons:
    1. I can use them for different functions, unless I don't want to share the values inside them, then I would declare other variables.
    2. Easier to track values in other functions; if I wanted to.

    But using static local variables is rather a new method to me and one member of Arduino forum provided me with a code that uses static local variables and I asked him why? and he told me that if I want to keep track of that variable.

    I tested it on codeblcoks and yes it's true that if I call the function multiple times with declaring the variables as static, I would keep track of the values, otherwise it would be the same and I can't change it.


    So, my questions are:
    1. What is the advantages / disadvantages of using static local variables ?

    2. Same question with global variables.

    3. What if I used static with a global variables ? Is it the scope to only that library ?

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    1. A static local variable has persistent state (due to static storage duration), but local scope. So you avoid name collisions and can manage the state in a more restricted portion of the program (e.g., if you don't return a pointer to it, then access to it remains confined to that function). This can be useful to solve certain problems (strtok would be an example), but it can also pose problems with reentrancy and thread safety, and surprise those who expected the function to be idempotent.

    2. A global variable has persistent/global state and global scope. This can sound good because you can access it from anywhere, but that boon is also a bane because you have to be constantly aware of the global state. This added mental load tends to make it more difficult to understand and reason about your program. Hence, you should keep them to a minimum.

    3. If you declared a global variable to be static, then it wouldn't be quite a global variable. It would have internal linkage, i.e., it would be a file scope variable such its name only refers to that object in that translation unit. So it only has file scope, not global scope. This can be useful if you have state that is inherently shared across the components of a library contained in a source file and are trying to restrict direct access to that state to just that library. Consequently, the mental load associated with global variables would be limited to just that file.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    May 2012
    Posts
    505
    C has three types of "global" variable

    Code:
    /* globals.c */
    int global; // a global, visible everywhere
    static int filescope; // visible everywhere in this file
    
    void foo(void)
    {
       static int local; // local to foo, but with persistent storage
    }
    "local" is physically stored in the same area of memory as "global" and "filescope". So it can be thought
    of as a sort of local global variable, if that isn't too contradictory for you.


    The disadvantage of "local" is that, because it is accessible from only one function, it's of limited practical
    use. Very few functions need to store state that they and only they can access. An exception is if
    you need to do set-up the first time a function is called. So you can have a "called" flag which is
    initially zero. You test it on function entry, do the set up if it is zero, and set it to one.

    "global" has the opposite problem. It's visiable everywhere in the program. Whilst in complex programs
    you often need one or two global variables, the more you have the more likely it is the prpgram
    will get into a tangled state, and the harder it is to test.

    filescope variables are the type most often used. They can only be accessed by functions in the same
    file, so it is easier to check that they are always being used correctly. And you quite often want
    several fucntions to operate on the same data. The filescope variable might be a pointer to the
    screen buffer. You set it up in one function by querying the system for a "screen", then you
    access it with functions like clear_screen() and write_pixel(), then you shut it down in a cleanup
    function.

    It would be nice to have library scope globals, but currenty this isn't possible in C.
    I'm the author of MiniBasic: How to write a script interpreter and Basic Algorithms
    Visit my website for lots of associated C programming resources.
    https://github.com/MalcolmMcLean


  4. #4
    Registered User
    Join Date
    Jan 2016
    Posts
    84
    Guys thank you so much. I understood the main ideas of your answers but not the full grasp.

    I'm actually working on a code for microcontroller lcd library. I want to avoid using for loops and implement more FSM code to have more flexible code that don't block the CPU with for/while/delay loops.

    I developed a console application but it was a first sketch, didn't reach the level of using the static/non static variables but there are some global variables.

    For now, I forgot about the static or non static variables.

    I would just put static for global variables to not conflict with other variables in other libraries in the same folder.

    I would post my current code, I have a new problem which is assigning a non-void function to a void function pointer.

    I don't know what to do. It actually producing a warning, so I can basically proceed my work and not caring about it but I decided to learn to solve all the warning because that is good to learn about programming rules and fundamentals.

    The problem is at line #23.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <string.h>
    #include <stdbool.h>
    // function 
    void write_chars(uint8_t row, uint8_t col, const char *str);
    
    
    // function pointers
    void (*fun_ptr)(void);      // main function pointer
    
    int main(){
    
    
        write_chars(0,0,str1);
    
    
        return 0;
    }
    
    void write_chars(uint8_t row, uint8_t col, const char *str){    if(!lock){
            fun_ptr = &write_chars; // <<<<<-- here is the problem
            state = CMD;
            if(graphics){graphics_set_mode(0);}
            i=0;
            counts = strlen(str);
            lock = 1;
        }
        // identify row/column location
        else{
            if        (row == 1)task_buffer[0] = (0x80 + (col - 1));
            else if    (row == 2)task_buffer[0] = (0x90 + (col - 1));
            else if    (row == 3)task_buffer[0] = (0x88 + (col - 1));
            else if    (row == 4)task_buffer[0] = (0x98 + (col - 1));
        }
    
    
        printf("%d",strlen(str));
    }

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    What's the purpose of fun_ptr?

    Anyway, the warning is legitimate: you're assigning a function pointer of one type to a function pointer of an incompatible type. You can easily fix this by changing the declaration of fun_ptr to:
    Code:
    void (*fun_ptr)(uint8_t, uint8_t, const char*);
    but whether this is the right thing to do depends on the purpose of fun_ptr.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    Registered User
    Join Date
    Jan 2016
    Posts
    84
    Sorry, I should have put the whole code so you know what I need the function pointer for.

    Line# 97 & 122.

    I just want this function pointer to take care of all the functions in this code, I don't want to have multiple ones.

    Its job is at line# 90.

    The function pointer is called whenever the task lock is ON means there still work to do, when it's finished the lock is OFF.

    Here is the code:

    Code:
    /*    Title:    function pointers    Date:    Thu, 30 July 2020
    */
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <string.h>
    #include <stdbool.h>
    #include <malloc.h>
    #include <math.h>
    
    // enumerations
    enum TASK_STATES{CMD, DATA, STRING};
    enum TASK_STATES state;
    
    // delay variables
    uint32_t dly_st, delay_period;
    bool dly_lock, lock;
    bool write_lock;
    uint16_t i, counter, counts;
    
    // command / data variables
    uint8_t str_buf;
    const char *str1 = {"hi how are you ?"};
    // basic pixel variables
    static uint8_t y,x, task_buffer[4];
    static bool row2_4, graphics;
    
    // functions
    void task_switcher(void);
    void task1(void);
    void task2(void);
    void write_chars(uint8_t row, uint8_t col, const char *str);
    void graphics_set_mode(bool mode);
    void transmit(uint8_t cmd);
    void delay_routine(void);
    
    // function pointers
    void (*fun_ptr)(void);      // main function pointer
    
    int main(){
    
        write_chars(0,0,str1);
    
        return 0;
    }
    
    void task_switcher(void){
        if(!dly_lock){// && lock
    //////////////////////////////////////////////////////
    // lcd transmisstion commands/data
            switch(state){
                case CMD:
                    if(counter<2){
                        transmit(task_buffer[counter]);
                        counter++;
                    }
                    else if(counts == 2){write_lock = 0;counts = 0;}
                    else{state = DATA;}
                break;
                case DATA:
                    if(counter<4){
                        transmit(task_buffer[counter]);
                        counter++;
                    }
                    else{
                        write_lock = 0;
                        counter = 0;
                        state = CMD;
                        printf("\n");
                    }
                break;
    
    
                case STRING:
                    if(i<16){
                        transmit(str_buf);
                        i++;
                        state = STRING;
                    }
                    else{
                        write_lock = 0;
                    }
    
    
                break;
            }
        }
        else {delay_routine();}           // first check delay flag
        if(write_lock){task_switcher();}  // still between cmd1-data2
        else if(lock){fun_ptr();}         // method2 function pointer
        else if(!write_lock){lock = 0;}   // finished writes ? : clear lock
    }
    
    
    void write_chars(uint8_t row, uint8_t col, const char *str){
        if(!lock){
            fun_ptr = &write_chars;               // <<------------- here
            state = CMD;
            if(graphics){graphics_set_mode(0);}
            i=0;
            counts = strlen(str);
            lock = 1;
        }
        // identify row/column location
        else{
            if        (row == 1)task_buffer[0] = (0x80 + (col - 1));
            else if    (row == 2)task_buffer[0] = (0x90 + (col - 1));
            else if    (row == 3)task_buffer[0] = (0x88 + (col - 1));
            else if    (row == 4)task_buffer[0] = (0x98 + (col - 1));
        }
    
    
        printf("%d",strlen(str));
    
    
    }
    
    
    // graphics mode
    void graphics_set_mode(bool mode){
        if(!lock){
            fun_ptr = &graphics_set_mode;   // <<------------- and here
            state = CMD;
            task_buffer[0] = 1;
            write_lock = 0;
            lock = 1;
        }
        if(mode){
            task_buffer[0] = 11;
            task_buffer[1] = 22;
            graphics = 1;
        }
        else{
            task_buffer[0] = 33;
            task_buffer[1] = 44;
            graphics = 0;
        }
        write_lock = 1;
        task_switcher();
    }
    
    
    void task2(void){
        if(!lock){
            fun_ptr = &task2;
            state = CMD;
            x = 0; y = 0; counter = 0;
            lock = 1; row2_4 = 0; write_lock = 0;
        }
    
    
        if(y<2 && !row2_4){         // 1st half of lcd
            task_buffer[0] = y;   task_buffer[1] = x;
            task_buffer[2] = 'E';     task_buffer[3] = 'F';
        }
    
    
        if(y<4 && row2_4){         // 2nd half of lcd
            task_buffer[0] = y;   task_buffer[1] = x;
            task_buffer[2] = 'G'; task_buffer[3] = 'H';
        }
        x++; if(x>7){y++;x=0;}
        if(y>1){row2_4 = 1;}
        if(y>3){row2_4 = 0;lock = 0;}
    
    
        write_lock = 1;
        task_switcher();
    }
    
    
    void task1(void){
        if(!lock){
            fun_ptr = &task1;
            state = CMD;
            x = 0; y = 0; counter = 0;
            lock = 1; row2_4 = 0; write_lock = 0;
        }
    
    
        if(y<2 && !row2_4){         // 1st half of lcd
            task_buffer[0] = y;   task_buffer[1] = x;
            task_buffer[2] = 'A'; task_buffer[3] = 'B';
        }
    
    
        if(y<4 && row2_4){         // 2nd half of lcd
            task_buffer[0] = y;   task_buffer[1] = x;
            task_buffer[2] = 'C'; task_buffer[3] = 'D';
        }
        x++; if(x>7){y++;x=0;}
        if(y>1){row2_4 = 1;}
        if(y>3){row2_4 = 0;lock = 0;}
    
    
        write_lock = 1;
        task_switcher();
    }
    
    
    // command tx
    void transmit(uint8_t cmd){
        if(state == CMD)      {printf("%d\t",cmd);}
        else                   {printf("%c\t",cmd);}
    }
    
    
    // delay routine
    void delay_routine(void){if(dly_lock){dly_lock = 0;}}
    Last edited by wolfrose; 08-04-2020 at 07:54 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. How do the global and local variables use the RAM?
    By YuminZhao in forum C++ Programming
    Replies: 2
    Last Post: 09-04-2011, 10:45 AM
  2. Declaring Global Variables
    By renanmzmendes in forum C++ Programming
    Replies: 2
    Last Post: 01-05-2008, 01:50 PM
  3. Local vs Global Variables
    By BENCHMARKMAN in forum C++ Programming
    Replies: 5
    Last Post: 07-03-2007, 05:17 AM
  4. Replies: 2
    Last Post: 10-02-2004, 10:12 AM
  5. Replies: 5
    Last Post: 06-01-2002, 11:24 PM

Tags for this Thread