Инициализация статической переменной внутри функции в C - PullRequest
0 голосов
/ 07 декабря 2018

Рассмотрим следующую функцию

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

}

Поскольку переменная не инициализирована постоянной времени компиляции, я не могу объявить ее без ошибок. Есть две причины, по которым я хочу сохранить переменную как статическуюпеременная внутри функции

1) Переменная не используется нигде в программе.Таким образом, нет необходимости сохранять его как глобальную переменную

2) Предыдущая функция должна быть инициализирована для текущего входа, иначе во время начального запуска разница между текущим входом и предыдущим входом может быть очень высокой из-заэнкодер подключен к токовому входу (и невозможно определить, где может быть значение энкодера, которое зависит от того, насколько пользователь повернул его перед выключением).Это приведет к ложному срабатыванию других функций.

Есть ли способ объявить статическую переменную внутри функции и инициализировать ее значением, аналогичным приведенному выше в примере?

Примечание.часть сложной программы, и я упростила ее, чтобы избежать сложности.Если в этом вопросе есть какая-то двусмысленность, пожалуйста, дайте мне знать

Ответы [ 3 ]

0 голосов
/ 07 декабря 2018

Вы можете изначально установить значение на некоторое значение по умолчанию и при первом вызове метода проверить, было ли значение инициализировано или нет.Если нет, то инициализируйте его.

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;
}
0 голосов
/ 07 декабря 2018

Есть ли способ объявить статическую переменную внутри функции и инициализировать ее значением, аналогичным приведенному выше примеру?

Я вижу еще одну проблему и предлагаю идею, которая решает обе проблемы.

Переполнение в вычитании

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

Учитывая, что previous_input, current_input может независимо быть любым из 2 32 , разница составляет около 2 33 разные результаты.С int как 32-битным, код может переполниться (UB) и не может различить это однозначно.На исключительных платформах с 64-битной int разница хорошо рассчитана, но теперь функциональность отличается от 32-битной платформы.

Рассмотрите возможность использования int64_t, так как требуется 33+ битная математика.

#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

С другой стороны, если не все 2 32 комбинации возможны и вычитание и сравнение хорошо вписываются в 32-битную математику, тогда используйте зарезервированное значение. @ user3386109 и просто определить, что нужно выполнить для инициализации.

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

Мне нравится идея отдельного флага static, предложенного другими.Но хотел предложить другой подход.

IAC, код, в общем, нуждается в защите с previous_input - current_input

0 голосов
/ 07 декабря 2018

Вы можете , если вы осторожны с дополнительной переменной:

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;
}

ОБНОВЛЕНИЕ:

Если current_input взято из read_encoder, вот очищенная версия, которая предотвращает двойное чтение в первый раз.

Также изначально я использовал дополнительную переменную flag, которая необходима, если есть нет значений за пределами.Но я включил вторую версию, которая на немного быстрее [если менее безопасна], которая использует одну переменную:

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;

    // ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...