Initialisation d'un tableau de structures

Dec 20 2020

Je me suis défini une structure:

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

J'ai pu initialiser une instance de cela comme ceci:

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

Cependant, lorsque j'essaye de les avoir dans un tableau:

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

J'obtiens cette erreur

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

Et je n'ai aucune idée de ce que je fais de mal ici. Vous pouvez voir le changement complet ici sur GitHub

Réponses

8 EdgarBonet Dec 20 2020 at 21:17
led h_red = {0,0,255,0,300};

Ici, vous définissez une variable et vous lui donnez en même temps une valeur initiale. C'est ce qu'on appelle une initialisation .

led leds[LEDS];

Ici, vous définissez un tableau. Puisqu'il est dans la portée globale et n'est pas explicitement initialisé, il est implicitement initialisé à tous les octets zéro.

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

Ici, vous essayez de donner une valeur à un élément du tableau qui a déjà été défini précédemment. Ce n'est donc pas une initialisation, mais une affectation . Contrairement aux initialisations, les affectations ne peuvent pas exister en dehors d'une fonction. Si vous souhaitez attribuer des valeurs initiales, vous pouvez le faire dans setup().

Vous pouvez également initialiser le tableau pendant que vous le définissez:

led leds[LEDS] = {
    {0, 0,   0, 0,   0},
    {0, 0,   0, 0,   0},
    {0, 0, 255, 0, 300}
};
GabrielStaples Dec 23 2020 at 04:18

J'ai voté pour la réponse de @Edgar Bonet , car elle est correcte.

Je veux cependant ajouter quelques exemples et explications supplémentaires.

Résumé clé:

En C et C ++, vous ne pouvez PAS avoir de logique de code en dehors des fonctions. Le contexte global en dehors des fonctions est destiné aux déclarations , aux définitions et à certaines initialisations / constructeurs uniquement. Toute la logique de code doit être à l' intérieur d'une fonction . La logique du code comprend les affectations de variables post-construction, les ifinstructions, etc.

Exemples:

1. NON autorisé:

Par conséquent, vous ne pouvez PAS effectuer les opérations suivantes, car il tente d'effectuer des affectations non initialisantes en dehors de toutes les étendues de fonction.

Notez également qu'en C ++ (ce qu'Arduino est), vous n'avez pas non plus besoin d'utiliser typedefpour les structs, donc j'ai supprimé cela de la structdéfinition. J'utilise également les types stdint.h , qui sont considérés comme plus sûrs et «meilleures pratiques» pour les types de données, car ils spécifient la taille exacte du type en bits. Utilisez uint8_tà la place de unsigned char, uint32_tau lieu de l'Arduino Uno unsigned long, et à la uint16_tplace de l'Arduino Uno unsigned int. En outre, en C ++ en particulier, constexprou les énumérations sont préférables #defineà la définition de constantes de variables.

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: Variable (re)assignments are NOT allowed outside of functions in 
// C and 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. EST autorisé:

Vous POUVEZ cependant avoir des initialisations de variables en dehors des fonctions, tant qu'elles se produisent en même temps que la construction , donc ceci est parfaitement valide:

Led leds[NUM_LEDS];
// This form of aggregate initialization during construction is just fine in the 
// global scope outside of all functions. 
Led leds[NUM_LEDS] = {
    {0, 0,   0, 0,   0},
    {0, 0,   0, 0,   0},
    {0, 0, 255, 0, 300},
};

void setup()
{
}

void loop()
{
}

3. EST également autorisé:

Ou, vous pouvez simplement déplacer vos réaffectations dans une fonction, telle que setup():

Led leds[NUM_LEDS];

void setup()
{
    // This variable (re)assignment is just fine since it's inside 
    // of a function.
    leds[0] = {0, 0,   0, 0,   0};
    leds[1] = {0, 0,   0, 0,   0};
    leds[2] = {0, 0, 255, 0, 300};
}

void loop()
{
}

4. Exemple complet et exécutable sur un PC:

Voici un exemple complet et exécutable sur un PC, avec une impression pour vérifier que le contenu de la structure a été modifié:

Exécutez-le en ligne vous-même: https://onlinegdb.com/MnEOQgCQT.

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

// Get the number of elements in a C-style array 
#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;
};

// To initialize once at construction. This form of aggregate initialization 
// can be used anywhere: both inside and outside functions. 
Led leds[NUM_LEDS] = {
    { 1,  2,  3,  4,  5},
    { 6,  7,  8,  9, 10},
    {11, 12, 13, 14, 15},
};

// Print the full contents of an array of `Led` structs
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");
    
    // Do this to set or change the structs at any time AFTER construction!
    // This variable (re)assignment is only allowed inside of a function, NOT 
    // in the global scope outside of all functions!
    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;
}

Exemple de sortie:

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

Autres références:

  1. https://en.cppreference.com/w/cpp/language/aggregate_initialization
  2. [ma réponse] https://stackoverflow.com/questions/61240589/how-to-initialize-a-struct-to-0-in-c/61240590#61240590