switch и структурированный массив - ошибка expression must have a constant value -- attempt to access run-time storage

traveler
Offline
Зарегистрирован: 27.09.2018

Добрый день! Прошу помочь знатоков С++ и Arduino. Записываю массив данных в структурированный массив. После чего мне необходимо обработать данные оператором switch. Фрагмент кода:

#include <Arduino.h>

const uint8_t cntPins = 8;
struct listData_t
{
  const uint8_t pinNumsber;
  const uint8_t pinID;
};
const listData_t pins[cntPins] = 
{
  {32, 2},  {34, 3},  {36, 4},  {38, 14}, {40, 15}, {42, 11}, {44, 13}, {46, 5}
};


void setup() 
{
  Serial.begin(115200);
  Serial.println(F("Start..."));

  for (uint8_t i=0; i<cntPins; i++)
    {
      Serial.print(pins[i].pinNumsber);
      Serial.print(F("\t"));
      Serial.println(pins[i].pinID);
    }
}

void loop()
{
  delay(1500);
  for (uint8_t i=0; i<cntPins; i++)
    {
      switch (pins[i].pinID)
      {
        case pins[0].pinID:
          Serial.print(F("pinNumber > "));
          Serial.println(pins[i].pinNumsber);
        break;
      }
    }
}

При компиляции возвращаются 2 ошибки:
expression must have a constant value -- attempt to access run-time storage
the value of 'pins' is not usable in a constant expression.

Если в case поставить const uint8_t N, то копилируется без ошибок и код работает. Кто может подсказать в какую сторону "копать"?

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

А вот чем Вам двумерный массив не нравится? Или там более глобальные замыслы?

Попробуйте в 3 строке проименить #define cntPins 8

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

здесь

     case pins[0].pinID:

должна быть целая константа 

Например 

   case 10: ....

   case 'a': ...

и т.д.

traveler
Offline
Зарегистрирован: 27.09.2018

DetSimen пишет:

здесь

     case pins[0].pinID:

должна быть целая константа 

Например 

   case 10: ....

   case 'a': ...

и т.д.

Я это понимаю, вопрос, есть вариант подставить в case целую константу, получив ее из массива?
Получается, мне нужно или дублировать константу, которую подставлять в case, или уходить на одномерные массивы, что очень не удобно и не желательно, или сначала, перед switch "выдергивать" данные из массива в локальные переменные, которые подставлять в case, что тоже, как-то кривовато... Может есть, какой-то вариант, я не профессионал в данном вопросе, поэтому и прошу подсказку в какую сторону копать...

traveler
Offline
Зарегистрирован: 27.09.2018

mykaida пишет:

А вот чем Вам двумерный массив не нравится? Или там более глобальные замыслы?

Попробуйте в 3 строке проименить #define cntPins 8

количество записей в массиве - не проблема, проблема в целочисленной константе, которую "кушает" case...

Да, задумка более глобальная, нежели во фрагменте кода...

sadman41
Offline
Зарегистрирован: 19.10.2016

traveler пишет:

Я это понимаю, вопрос, есть вариант подставить в case целую константу, получив ее из массива?

Константа в case должна быть доступна на момент компиляции. Т.е. напрямую или через подстановку. Но никак не по вычисляемому на этапе исполнения индексу массива. Select-case в объектном коде выглядит набором джампов (считай goto), поэтому адреса "приземлений" должны быть вычислены при компиляции.

traveler пишет:

Получается, мне нужно или дублировать константу, которую подставлять в case, или уходить на одномерные массивы, что очень не удобно и не желательно, или сначала, перед switch "выдергивать" данные из массива в локальные переменные, которые подставлять в case, что тоже, как-то кривовато... Может есть, какой-то вариант, я не профессионал в данном вопросе, поэтому и прошу подсказку в какую сторону копать...

Чтобы понять куда копать - надо узнать для чего копать. Если бы граф Монте-Кристо копал без понимания направления, то скелет его нашли бы в каземате.

Green
Offline
Зарегистрирован: 01.10.2015

Ну не обязательно же через switch - case делать. Можно ведь и через if - else if конструкцию.

traveler
Offline
Зарегистрирован: 27.09.2018

Green пишет:

Ну не обязательно же через switch - case делать. Можно ведь и через if - else if конструкцию.

Громостко и неудобно получается, если if и else if использовать...

traveler
Offline
Зарегистрирован: 27.09.2018

sadman41 пишет:

Чтобы понять куда копать - надо узнать для чего копать. Если бы граф Монте-Кристо копал без понимания направления, то скелет его нашли бы в каземате.

Получается выход один, вычислить все переменные, хранящиеся в многомерных массивах до их использования в операторе switch и case... Другого выходе нет?!

Для чего копать:
1. Хранить данные в многомерном структурированном массиве
2. Использовать switch и case используя данные их многомерных структурированных массивов

sadman41
Offline
Зарегистрирован: 19.10.2016

traveler пишет:

2. Использовать switch и case используя данные их многомерных структурированных массивов

Использовать для... <тут пример использования>

Green
Offline
Зарегистрирован: 01.10.2015

traveler пишет:

Громостко и неудобно получается, если if и else if использовать...


Что же там громоЗДкого! Даже компактнее получится. А если нужны условные break-и, то их можно ретурном заментить, если оформить в функции.

traveler
Offline
Зарегистрирован: 27.09.2018

sadman41 пишет:

Использовать для... <тут пример использования>

Как пример использования:

struct listBTN_t
{
  const uint8_t idBTN;
  const char nameBTN[5];
  const char textBTN[5];
};
const listBTN_t buttons[3] =
{
  {0, "bt10", "t10"},
  {1, "bt11", "t11"},
  {2,    "bt12", "t12"}
};

switch (RXdata)
{
case buttons[0].idBTN:
// некоторая последовательность функций
break;
case buttons[1].idBTN:
// некоторая последовательность функций
break;
case buttons[2].idBTN:
// некоторая последовательность функций
break;
}

при этом RXdata это данные полученные по UART или RS-485

sadman41
Offline
Зарегистрирован: 19.10.2016

На поверхности лежит поиск в цикле соответствия RXData и idBTN. Switch нацеливается на переменную, в которую помещается найденный индекс элемента массива, который соответствует условию. Все индексы определены на этапе компиляции и проблемы не возникнет. Можно через define дать им осмысленные имена.

traveler
Offline
Зарегистрирован: 27.09.2018

sadman41 пишет:

На поверхности лежит поиск в цикле соответствия RXData и idBTN. Switch нацеливается на переменную, в которую помещается найденный индекс элемента массива, который соответствует условию. Все индексы определены на этапе компиляции и проблемы не возникнет. Можно через define дать им осмысленные имена.

Да, всё верно, полученные внешние данные я сравниваю с id кнопки, чтобы выполнить то или иное действие по нажатию локальной кнопки. Если явно задать имена, тогда при создании многомерного массива, писать в него не физические значения id, а имена, тем самым запишеться значение присвоеное через #define.

#define idName1 = 0
#define idName2 = 1
#define idName3 = 2

struct listBTN_t
{
  const uint8_t idBTN;
  const char nameBTN[5];
  const char textBTN[5];
};
const listBTN_t buttons[3] =
{
  {idName1, "bt10", "t10"},
  {idName2, "bt11", "t11"},
  {idName3,    "bt12", "t12"}
};

switch (RXdata)
{
case idName1:
// некоторая последовательность функций
break;
case idName2:
// некоторая последовательность функций
break;
case idName3:
// некоторая последовательность функций
break;
}

как-то так, или всё же есть более правильный способ, через #define?

sadman41
Offline
Зарегистрирован: 19.10.2016

Я имел в виду более сложный вариант, но, если idNameX никогда не будет несовместимого с case типа, то можно и на этом остановиться.  

traveler
Offline
Зарегистрирован: 27.09.2018

sadman41 пишет:

Я имел в виду более сложный вариант, но, если idNameX никогда не будет несовместимого с case типа, то можно и на этом остановиться.  

idNameX - всегда число (uint8_t или const uint8_t), как id компонента.

А какой более сложный вариант, если не сложно, пример дайте пожалуйста

sadman41
Offline
Зарегистрирован: 19.10.2016

Я его описал выше - поиск в цикле. Искомая строка сравнивается, например, с buttons[i].nameBTN, совпало - из цикла выскакиваем, найденный индекс (i) суём в switch. 

traveler
Offline
Зарегистрирован: 27.09.2018

sadman41 пишет:

Я его описал выше - поиск в цикле. Искомая строка сравнивается, например, с buttons[i].nameBTN, совпало - из цикла выскакиваем, найденный индекс (i) суём в switch. 

Спасибо! Невнимательно прочел тот пост.