Инициализация массива структур

Я определил себе структуру:

typedef struct {
  unsigned char current;
  unsigned char start;
  unsigned char target;
  unsigned long startTime;
  unsigned int duration;
} led;

Я смог инициализировать экземпляр этого следующим образом:

led h_red = {0,0,255,0,300};

Однако, когда я пытаюсь иметь их в массиве:

led leds[LEDS];
leds[0] = {0,0,0,0,0};
leds[1] = {0,0,0,0,0};
leds[2] = {0,0,255,0,300};

Я получаю эту ошибку

signal:28:1: error: 'leds' does not name a type
 leds[0] = {0,0,0,0,0};
 ^~~~
signal:29:1: error: 'leds' does not name a type
 leds[1] = {0,0,0,0,0};
 ^~~~
signal:30:1: error: 'leds' does not name a type
 leds[2] = {0,0,255,0,300};
 ^~~~

И я понятия не имею, что я здесь делаю не так. Вы можете увидеть полное изменение здесь, на GitHub

, 👍4


2 ответа


Лучший ответ:

10
led h_red = {0,0,255,0,300};

Здесь вы определяете переменную и в то же время даете ей начальное значение. Это называется инициализацией.

led leds[LEDS];

Здесь вы определяете массив. Поскольку он находится в глобальной области видимости и явно не инициализирован, он неявно инициализируется всеми нулевыми байтами.

leds[0] = {0,0,0,0,0};

Здесь вы пытаетесь придать значение элементу массива , который уже был определен ранее. Таким образом, это не инициализация, а присвоение. В отличие от инициализации, присваивания не могут существовать вне функции. Если вы хотите присвоить начальные значения, вы можете сделать это в setup().

Кроме того, вы можете инициализировать массив во время его определения:

led leds[LEDS] = {
    {0, 0,   0, 0,   0},
    {0, 0,   0, 0,   0},
    {0, 0, 255, 0, 300}
};
,

Это ключевая часть, на которую следует обратить внимание: ** В отличие от инициализации, назначения не могут существовать вне функции. Если вы хотите присвоить начальные значения, вы можете сделать это в setup().** Вызов OP leds[0] = {0,0,0,0,0}; вполне допустим в другой функции, такой как setup(), но НЕ разрешен за пределами всех областей функций, где может иметь место только инициализация. ОП случайно пытался выполнить это назначение в глобальной области, где новые назначения и обычный логический код не допускаются., @Gabriel Staples


1

Я поддержал ответ @Edgar Bonet, потому что он правильный.

Однако я хочу добавить еще несколько примеров и объяснений.

Ключевое резюме:

В C и C ++ вы НЕ можете иметь логику кода вне функций. Глобальный контекст вне функций предназначен только для объявлений, определенийи некоторых инициализаций/конструкторов. Вся логика кода должна быть внутри функции. Логика кода включает в себя назначения переменных после построения, операторы if и т. Д.

Примеры:

1. НЕ допускается:

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

Обратите внимание также, что в C ++ (которым является Arduino) вам также не нужно использовать typedef для структур, поэтому я удалил это из определения структуры. Я также использую типы stdint.h, которые считаются более безопасными и "лучшими практиками" для типов данных, поскольку они указывают точный размер типа в битах. Используйте uint8_t вместо unsigned char, uint32_t вместо unsigned long Arduino Unoи uint16_t вместо unsigned int Arduino Uno. Кроме того, в частности, в C ++ constexpr или перечисления предпочтительнее #define для установки переменных констант.

constexpr uint8_t NUM_LEDS = 3;

struct Led {
  uint8_t current;
  uint8_t start;
  uint8_t target;
  uint32_t startTime;
  uint16_t duration;
};

Led leds[NUM_LEDS];
// NOT OK: Присвоения переменных (re) НЕ допускаются вне функций в 
// C и C ++.
leds[0] = {0, 0,   0, 0,   0};
leds[1] = {0, 0,   0, 0,   0};
leds[2] = {0, 0, 255, 0, 300};

void setup()
{
}

void loop()
{
}

2. Допускается:

Однако вы МОЖЕТЕ иметь инициализации переменных вне функций, если они происходят одновременно с построением, так что это вполне допустимо:

Led leds[NUM_LEDS];
// Эта форма агрегатной инициализации во время построения просто прекрасна в
// глобальной области вне всех функций. 
Led leds[NUM_LEDS] = {
    {0, 0,   0, 0,   0},
    {0, 0,   0, 0,   0},
    {0, 0, 255, 0, 300},
};

void setup()
{
}

void loop()
{
}

3. Также допускается:

Или вы можете просто переместить переназначения в функцию, например setup():

Led leds[NUM_LEDS];

void setup()
{
    // Это назначение переменной (re) просто отлично, так как она находится внутри 
    // функции.
    leds[0] = {0, 0,   0, 0,   0};
    leds[1] = {0, 0,   0, 0,   0};
    leds[2] = {0, 0, 255, 0, 300};
}

void loop()
{
}

4. Полный, выполнимый пример на ПК:

Вот полный, выполняемый пример на ПК с печатью, чтобы убедиться, что содержимое структуры было изменено:

Запустите его онлайн самостоятельно: https://onlinegdb.com/MnEOQgCQT.

#include <stdint.h>
#include <stdio.h>

// Получить количество элементов в массиве C-стиля 
#define ARRAY_LEN(array) (sizeof(array)/sizeof(array[0]))

constexpr uint8_t NUM_LEDS = 3;

struct Led {
  uint8_t current;
  uint8_t start;
  uint8_t target;
  uint32_t startTime;
  uint16_t duration;
};

// Инициализировать один раз при построении. Эта форма агрегатной инициализации 
// может использоваться в любом месте: как внутри, так и снаружи. 
Led leds[NUM_LEDS] = {
    { 1,  2,  3,  4,  5},
    { 6,  7,  8,  9, 10},
    {11, 12, 13, 14, 15},
};

// Печать полного содержимого массива структур `Led`
void printLeds(const Led ledArrayIn[], size_t ledArrayLen)
{
    for (size_t i = 0; i < ledArrayLen; i++)
    {
        printf("ledArrayIn[%lu]\n"
               "current   = %u\n"
               "start     = %u\n"
               "target    = %u\n"
               "startTime = %u\n" 
               "duration  = %u\n\n",
               i,
               ledArrayIn[i].current,
               ledArrayIn[i].start,
               ledArrayIn[i].target,
               ledArrayIn[i].startTime,
               ledArrayIn[i].duration);
    }
}

int main()
{
    printf("Hello World\n\n");

    printLeds(leds, ARRAY_LEN(leds));
    
    printf("==============\n\n");
    
    // Сделайте это, чтобы установить или изменить структуры в любое время ПОСЛЕ построения!
    // Это присвоение переменной (re) разрешено только внутри функции, А НЕ 
    // в глобальной области вне всех функций!
    leds[0] = {10, 20,  30,  40,  50};
    leds[1] = {60, 70,  80,  90, 100};
    leds[2] = { 0,  0, 255,   0, 300};
    
    printLeds(leds, ARRAY_LEN(leds));

    return 0;
}

Пример вывода:

Hello World

ledArrayIn[0]
current   = 1
start     = 2
target    = 3
startTime = 4
duration  = 5

ledArrayIn[1]
current   = 6
start     = 7
target    = 8
startTime = 9
duration  = 10

ledArrayIn[2]
current   = 11
start     = 12
target    = 13
startTime = 14
duration  = 15

==============

ledArrayIn[0]
current   = 10
start     = 20
target    = 30
startTime = 40
duration  = 50

ledArrayIn[1]
current   = 60
start     = 70
target    = 80
startTime = 90
duration  = 100

ledArrayIn[2]
current   = 0
start     = 0
target    = 255
startTime = 0
duration  = 300

Другие ссылки:

  1. https://en.cppreference.com/w/cpp/language/aggregate_initialization
  2. [мой ответ] https://stackoverflow.com/questions/61240589/how-to-initialize-a-struct-to-0-in-c/61240590#61240590
,

Что касается первого абзаца вашего ответа; Что означает "Я проголосовал за ответ @Edgar Bonet, потому что он правильный". это имеет отношение к вопросу?, @VE7JRO