Поддерживает ли Arduino struct hack или подобное решение вместо гибких элементов массива?

Я написал проект Arduino для своего сына и в процессе узнал о C. Все работает нормально, но после разделения кода на десять файлов и группировки переменных в структуры в каждом файле я не могу решить одно желание для ясности. Нам нужно эмпирически определить наилучший размер массива для хранения и усреднения чтения портов, поэтому это то, что я хочу:

struct Alarms {
  // Configurable parameters
    const unsigned int number_of_reads = 24;
  // State variables
    int reads[number_of_reads]; // Error: invalid use of non-static data member 'Alarms::num_of_reads'
};

Это просто, но не работает. Я пробовал гибкие элементы массива, пока не обнаружил, что эта функция не поддерживается в C++. Ардуино компилируется на С++. Я пробовал много примеров «взлома структуры», но все они возвращали ошибки, подобные этой:

struct Alarms {
  // Configurable parameters
    int number_of_reads = 24;
  // State variables
    int reads[];
} ar;

void setup_alarm() {
    ar.reads = malloc(sizeof(int) * ar.number_of_reads);  // Error: incompatible types in assignment of 'void*' to 'int [0]'
}

Это выглядело многообещающе, но я подозреваю, что мое невежество ярко светится. Большинство примеров взлома структуры требуют объявления структуры и последующей инициализации переменных структуры. Я надеюсь не дублировать структуру.

Я подумал о разделении структуры, но это было бы подвержено ошибкам и, ну, еще одна ошибка компиляции:

struct Alarms2 {
    int reads[ar.num_of_reads];  // Error: array bound is not an integer constant before ']' token
} ar2;

Альтернативой является размер массива и получение размера позже, но это требует объяснения:

struct Alarms {
  // Configurable parameters
    int reads[ 24 ];  // Put number of reads to average between brackets
  // State variables
    int number_of_reads;
};

void setup_alarm() {
    ar.number_of_reads = sizeof(ar.reads) / sizeof(ar.reads[0]);  // this works
}

Есть ли способ взломать структуру или какое-то подобное решение в Arduino, чтобы получить первый пример?


person Buoy    schedule 20.12.2018    source источник


Ответы (1)


Размер структуры должен быть известен во время компиляции. Константные типы данных в структурах могут изменяться для каждого экземпляра структуры, поэтому вы получаете недопустимое использование нестатического члена данных «Alarms::num_of_reads» при попытке инициализировать свой массив. Лучший способ решить эту проблему — использовать функции init_alarm и destroy_alarm. Вот так ...

#include <stdio.h>
#include <stdlib.h>

#define DEFAULT_NUM_OF_READS (24)

struct alarm {
    // Configurable parameters
    const int number_of_reads;
    // State variables
    int *reads;
};

void init_alarm(struct alarm *alarm)
{
    alarm->reads = (int *) malloc(alarm->number_of_reads * sizeof(int));
}

void destroy_alarm(struct alarm *alarm)
{
    free(alarm->reads);
}

int main(int argc, char **argv)
{
  // When we create our struct, set number_of_reads to default
  struct alarm alarm = {.number_of_reads = DEFAULT_NUM_OF_READS, .reads = NULL};

  init_alarm(&alarm);

  alarm.reads[0] = 13;
  alarm.reads[23] = 100;

  printf("alarm.reads[0] = %d, alarm.reads[23] = %d\n", alarm.reads[0], alarm.reads[23]);

  destroy_alarm(&alarm);

  return 0;
}

Примечание. Чтобы использовать назначенный инициализатор для инициализации структуры, вы должны скомпилировать его с помощью ANSI (C99) следующим образом...

gcc --std=c99 test.c -o test

person Stefan Bossbaly    schedule 20.12.2018
comment
Я успешно скомпилировал и запустил ваше интересное решение с помощью gcc, но у меня есть некоторые препятствия, чтобы заставить его работать в мире Arduino. Я работаю над частью этого сейчас. Arduino IDE не предлагает установку флага компилятора, а функция main() скрыта. Если я использую #define DEFAULT_NUM_OF_READS (24), я могу просто инициализировать массив чтением int[DEFAULT_NUM_OF_READS]. Я надеюсь управлять всеми значениями в структурах. - person Buoy; 21.12.2018
comment
Вы можете изменить флаги компиляции, отредактировав переменную compiler.c.flags в файле platform.txt. Подробнее об этом можно прочитать здесь . Если вы делаете reads[DEFAULT_NUM_OF_READS], вам больше не нужны функции init_alarm и destroy_alarm. Теперь размер структуры известен во время компиляции. Просто знайте, что вы не сможете изменить размер массива для каждой структуры. Все структуры alarm будут иметь массив reads размера 24. Ответ выше позволяет настроить размер для каждой структуры. - person Stefan Bossbaly; 21.12.2018