2

Consider the following function

int16_t read_input(void)
{
   static int32_t previous_input = read_encoder(); // <--Not a compile time constant

   //Read current_input 

   if (previous_input - current_input > SOME_THRESHLD)
       some_action();

   previous_input = current_input;

   //some more code + return statement

}

Since the variable is not initialised to a compile time constant I an not able to declare it without errors.There are 2 reasons why I want to keep the variable as static variable inside the function

1) The variable is not getting used anywhere else in the program. So there is no need of keeping it as a global variable

2) The previous function needs to be initialised to current input or else during the initial run the difference between current input and previous input can go very high because of the encoder connected to current input (and there is no way of telling where could be the encoder value which depends on how much the user has rotated it before turning it off). This will create false triggering of other functions.

Is there any way of declaring a static variable inside a function and initializing it to value similar to example given above?

Note : This problem is a part of a complex program and I have simplified it to avoid complexity. If there is any ambiguity in the question please let me know

3
  • I'm unclear why being static is important here. Commented Dec 7, 2018 at 3:30
  • In addition to Craig's fine answer, you can also initialize previous_input to a value that read_encoder never returns. For example, if read_encoder returns a number between 0 and 1023, then initializing previous_input to -1 allows the code to detect that there was no previous input. Commented Dec 7, 2018 at 3:38
  • @DaveNewton:- The only location where I use previous_input is inside the read_input function and it needs to preserve the value between function calls Commented Dec 7, 2018 at 4:40

3 Answers 3

3

You can if you're careful with an extra variable:

int16_t
read_input(void)
{
    static int32_t previous_input = 0;
    static int first_time = 1;

    if (first_time) {
        first_time = 0;
        previous_input = read_encoder();
    }

    // Read current_input

    if (previous_input - current_input > SOME_THRESHLD)
        some_action();

    previous_input = current_input;
}

UPDATE:

If current_input comes from read_encoder, here's a cleaned up version that prevents a double read on the first time.

Also, originally, I used an extra flag variable, which is necessary if there are no out of bounds values. But, I've included a second version that is slightly faster [if less safe] that uses the single variable:

int16_t
read_input(void)
{
    static int32_t previous_input = 0;
    static int first_time = 0;
    int32_t current_input;

    // Read current_input
    current_input = read_encoder();

    if (first_time) {
        first_time = 0;
        previous_input = current_input;
    }

    if (previous_input - current_input > SOME_THRESHLD)
        some_action();

    previous_input = current_input;
}

#define OUT_OF_BOUNDS   -1

int16_t
read_input2(void)
{
    static int32_t previous_input = OUT_OF_BOUNDS;
    int32_t current_input;

    // Read current_input
    current_input = read_encoder();

    if (previous_input == OUT_OF_BOUNDS)
        previous_input = current_input;

    if (previous_input - current_input > SOME_THRESHLD)
        some_action();

    previous_input = current_input;

    // ...
}
Sign up to request clarification or add additional context in comments.

Comments

2

You can initially set the value to some default value and on first calling the method, check if the value has been initialised or not. If not then initialise it.

int16_t read_input(void)
{
   static int32_t previous_input = 0; // or a value indicating 'not initialised'
   if (previous_input == 0) previous_input = read_encoder();

   //Read current_input 

   if (previous_input - current_input > SOME_THRESHLD)
       some_action();

   previous_input - current_input;
}

1 Comment

Keeping the previous_input to a value indicating 'not initialized' will solve my problem. But I have one more question which is not important at this point - What if the previous_input stores a value which is -SOME_LIMIT to +SOME_LIMIT. for instance, it is attached to a continuous rotation rotary encoder. In this case, the SOME_LIMIT value is determined by the datatype storing the value and it overflows only when the datatype limit is exceeded.
2

Is there any way of declaring a static variable inside a function and initializing it to value similar to example given above?

I see another concern and offer an idea the solves both.

Overflow in the subtraction

if (previous_input - current_input > SOME_THRESHLD)  // OF possible

Given previous_input, current_input could independently be any of 232, the difference has about 233 different results. With int as 32-bit, code can overflow (UB) and cannot distinguish that uniquely. On exceptional platforms with 64-bit int, the difference is well calculated, yet now functionality differs from 32-bit platforms.

Consider using int64_t since 33+ bit math is needed.

#define SPECIAL_BIG (INT64_MAX/2)
static int64_t previous_input = SPECIAL_BIG;
if (previous_input == SPECIAL_BIG) {
   previous_input = read_encoder();  // first time
}
...
if (previous_input - current_input > SOME_THRESHLD) {
    some_action();
  }
}
...
if (previous_input - current_input > SOME_THRESHLD)  // OF not possible

On the other hand, if not all 232 combinations possible and the subtraction and compare well fit in 32-bit math, then use a reserved value. @user3386109 and simple detect that to perform initialization.

static int32_t previous_input = SPECIAL.
if (previous_input == SPECIAL) {
  previous_input = read_encoder();  // first time
}

I like the idea of a static separate flag as suggested by others. But wanted to offer another approach.

IAC, code, in general, needs OF protection with previous_input - current_input

3 Comments

You might want to add that the reason for the possible overflow is that these are signed integers.
@GermanNerd I agree mostly. Yet the possibility of mathematical overflow applies if the type is signed or unsigned integer. Of course with unsigned the OF does not beget UB, yet it is mathematical the incorrectly answer with previous_input - current_input > SOME_THRESHLD.
Yes, I am aware of that. I just thought that possibly the OP will have trouble grasping why these overflows occur, and what the consequences are. I guess not everyone easily understands why INT32_MIN - INT32_MAX requires, as you say, 33-bit math.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.