Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Industrial Internet of Things >> Embarqué

Comprendre le C intégré :que sont les structures ?

Après avoir présenté les structures, nous examinerons certaines des applications importantes de ce puissant objet de données. Ensuite, nous examinerons la syntaxe du langage C pour déclarer une structure. Enfin, nous présenterons brièvement l'exigence d'alignement des données. Nous verrons que nous pourrons peut-être réduire la taille d'une structure en réorganisant simplement l'ordre de ses membres.

Cet article fournit des informations de base sur les structures dans la programmation C embarquée.

Après avoir présenté les structures, nous examinerons certaines des applications importantes de ce puissant objet de données. Ensuite, nous examinerons la syntaxe du langage C pour déclarer une structure. Enfin, nous présenterons brièvement l'exigence d'alignement des données. Nous verrons que nous pourrons peut-être réduire la taille d'une structure en réorganisant simplement l'ordre de ses membres.

Structures

Un certain nombre de variables du même type qui sont logiquement liées les unes aux autres peuvent être regroupées sous forme de tableau. Travailler sur un groupe plutôt que sur une collection de variables indépendantes nous permet d'organiser les données et de les utiliser plus commodément. Par exemple, nous pouvons définir le tableau suivant pour stocker les 50 derniers échantillons d'un CAN qui numérise une entrée vocale :

uint16_t voix[50] ; 

Notez que uint16_t est un type entier non signé avec une largeur d'exactement 16 bits. Ceci est défini dans la bibliothèque standard C stdint.h , qui fournit des types de données d'une longueur de bit spécifique indépendante des spécifications du système.

Les tableaux peuvent être utilisés pour regrouper un certain nombre de variables qui sont du même type de données. Que faire s'il existe une connexion entre des variables de différentes Types de données? Pouvons-nous traiter ces variables comme un groupe dans notre programme ? Par exemple, supposons que nous devons spécifier le taux d'échantillonnage de l'ADC qui génère la voix tableau ci-dessus. Nous pouvons définir une variable flottante pour stocker le taux d'échantillonnage :

float sample_rate ; 

Bien que les variables voix et sample_rate sont liés l'un à l'autre, ils sont définis comme deux variables indépendantes. Pour associer ces deux variables entre elles, nous pouvons utiliser une puissante construction de données du langage C appelée structure. Les structures nous permettent de regrouper différents types de données et de les traiter comme un seul objet de données. Une structure peut inclure différentes sortes de types de variables telles que d'autres structures, des pointeurs vers des fonctions, des pointeurs vers des structures, etc. Pour l'exemple vocal, nous pouvons utiliser la structure suivante :

struct record { uint16_t voice[50] ; float sample_rate;}; 

Dans ce cas, nous avons une structure appelée record qui a deux membres ou champs différents :le premier membre est un tableau de uint16_t éléments, et le deuxième membre est une variable de type float. La syntaxe commence par le mot-clé struct . Le mot après le mot-clé struct est un nom facultatif utilisé pour référencer la structure plus tard. Nous discuterons d'autres détails sur la définition et l'utilisation des structures dans le reste de l'article.

Pourquoi les structures sont-elles importantes ?

L'exemple ci-dessus met en évidence une application importante des structures, c'est-à-dire la définition d'objets de données dépendant de l'application qui peuvent associer des variables individuelles de différents types les unes aux autres. Cela conduit non seulement à un moyen efficace de manipuler les données, mais nous permet également de mettre en œuvre des structures spécialisées appelées structures de données.

Les structures de données peuvent être utilisées pour diverses applications telles que la messagerie entre deux systèmes embarqués et le stockage de données recueillies à partir d'un capteur dans des emplacements de mémoire non contigus.

Figure 1. Les structures peuvent être utilisées pour implémenter une liste chaînée.

De plus, les structures sont des objets de données utiles lorsque le programme doit accéder aux registres d'un périphérique de microcontrôleur mappé en mémoire. Nous examinerons les applications de structure dans le prochain article.

Figure 2. Carte mémoire d'un MCU STM32. Image reproduite avec l'aimable autorisation de Embedded Systems with ARM.

Déclarer une structure

Pour utiliser des structures, nous devons d'abord spécifier un modèle de structure. Considérez l'exemple de code ci-dessous :

struct record { uint16_t voice[4] ; float sample_rate;}; 

Ceci spécifie une mise en page ou un modèle pour créer les futures variables de ce type. Ce modèle comprend un tableau de uint16_t et une variable de type float. Le nom du modèle est record , et cela vient après le mot-clé struct . Il est intéressant de mentionner qu'il n'y a pas d'allocation de mémoire pour stocker un modèle de structure. L'allocation de mémoire se produit uniquement après qu'une variable de structure basée sur cette disposition est définie. Le code suivant déclare la variable mic1 du modèle ci-dessus :

struct record mic1 ; 

Maintenant, une section de mémoire est allouée à la variable mic1 . Il a de l'espace pour stocker les quatre uint16_t éléments du tableau et une variable flottante.

Les membres d'une structure sont accessibles à l'aide de l'opérateur membre (.). Par exemple, le code suivant affecte 100 au premier élément du tableau et copie la valeur de sample_rate au fs variable (qui doit être de type float).

mic1.voice[0]=100;fs=mic1.sample_rate; 

Autres façons de déclarer une structure

Nous avons examiné une façon de déclarer des structures dans la section précédente. Le langage C prend en charge d'autres formats qui seront examinés dans cette section. Vous vous en tiendrez probablement à un format tout au long de vos programmes, mais se familiariser avec les autres peut parfois être utile.

La syntaxe générale pour déclarer le modèle d'une structure est :

struct tag_name { type_1 member_1 ; type_2 membre_2 ; … type_n membre_n;} nom_variable; 

Le nom_tag et nom_variable sont des identifiants facultatifs. Nous verrons généralement au moins un de ces deux identifiants, mais il existe des cas où nous pouvons les éliminer tous les deux.

Syntaxe 1 : Lorsque les deux tag_name et nom_variable sont présents, nous définissons la variable de structure juste après le modèle. En utilisant cette syntaxe, nous pouvons réécrire l'exemple précédent comme suit :

struct record { uint16_t voice[4] ; float sample_rate;} mic1; 

Maintenant, si nous devons définir une autre variable (mic2 ), on peut écrire

struct record mic2 ; 

Syntaxe 2 : Uniquement variable_name est inclus. En utilisant cette syntaxe, nous pouvons réécrire l'exemple de la section précédente comme suit :

struct { uint16_t voice[4] ; float sample_rate;} mic1; 

Dans ce cas, nous devons définir toutes nos variables juste après le modèle et nous ne pouvons définir aucune autre variable plus tard dans notre programme (car le modèle n'a pas de nom et nous ne pouvons pas nous y référer plus tard).

Syntaxe 3 : Dans ce cas, il n'y a pas de tag_name ou nom_variable . Les modèles de structure définis de cette manière sont appelés structures anonymes. Une structure anonyme peut être définie au sein d'une autre structure ou union. Un exemple est donné ci-dessous :

struct test { // Structure anonyme struct { float f; caractère a ; };} test_var; 

Pour accéder aux membres de la structure anonyme ci-dessus, nous pouvons utiliser l'opérateur membre (.). Le code suivant attribue 1.2 au membre f .

test_var.f=1.2 ; 

La structure étant anonyme, nous accédons à ses membres en utilisant l'opérateur membre une seule fois. S'il avait un nom comme dans l'exemple suivant, nous devrions utiliser l'opérateur membre deux fois :

struct test { struct { float f; caractère a ; } imbriqué;} test_var; 

Dans ce cas, nous devons utiliser le code suivant pour attribuer 1.2 à f :

test_var.nested.f=1.2 ; 

Comme vous pouvez le voir, les structures anonymes peuvent rendre le code plus lisible et moins verbeux. Il est également possible d'utiliser le mot-clé typedef avec une structure pour définir un nouveau type de données. Nous verrons cette méthode dans un prochain article.

Mise en page de la mémoire pour une structure

Le standard C garantit que les membres d'une structure seront placés en mémoire les uns après les autres dans l'ordre dans lequel les membres sont déclarés au sein de la structure. L'adresse mémoire du premier membre sera la même que l'adresse de la structure elle-même. Prenons l'exemple suivant :

struct Test2{ uint8_t c; uint32_t d; uint8_t e; uint16_t f;} MaStruct; 

Quatre emplacements mémoire seront alloués pour stocker les variables c, d, e et f. L'ordre des emplacements mémoire correspondra à celui de la déclaration des membres :l'emplacement pour c aura l'adresse la plus basse, puis d, e, et enfin, f apparaîtra. De combien d'octets avons-nous besoin pour stocker cette structure ? Compte tenu de la taille des variables, nous savons qu'au moins 1+4+1+2=8 octets sont nécessaires pour stocker cette structure. Cependant, si nous compilons ce code pour une machine 32 bits, nous observerons étonnamment que la taille de MyStruct est de 12 octets au lieu de 8 ! Cela est dû au fait qu'un compilateur a certaines contraintes lors de l'allocation de mémoire pour différents membres d'une structure. Par exemple, un entier de 32 bits ne peut être stocké qu'à des emplacements mémoire dont l'adresse est divisible par quatre. De telles contraintes, appelées exigences d'alignement des données, sont mises en œuvre pour permettre au processeur d'accéder plus efficacement aux variables. L'alignement des données entraîne une perte d'espace (ou de remplissage) dans la disposition de la mémoire. Ce sujet n'est présenté qu'ici ; nous passerons en revue les détails dans le prochain article de cette série.

Figure 3. L'alignement des données entraîne une perte d'espace (ou de remplissage) dans la disposition de la mémoire.

Étant conscients des exigences d'alignement des données, nous pouvons peut-être réorganiser l'ordre des membres au sein d'une structure et rendre l'utilisation de la mémoire plus efficace. Par exemple, si nous réécrivons la structure ci-dessus comme indiqué ci-dessous, sa taille diminuera à 8 octets sur une machine 32 bits.

struct Test2{ uint32_t d; uint16_t f; uint8_t c; uint8_t e;} MaStruct; 

Pour un système embarqué limité par la mémoire, réduire la taille d'un objet de données de 12 octets à 8 octets représente une économie importante, en particulier lorsqu'un programme nécessite un grand nombre de ces objets de données.

Le prochain article traitera plus en détail de l'alignement des données et examinera quelques exemples d'utilisation de structures dans des systèmes embarqués.

Résumé

Pour voir une liste complète de mes articles, veuillez visiter cette page.


Embarqué

  1. Que sont les vis de pont ?
  2. Que sont les joints à ressort ?
  3. Que sont les vis à bois ?
  4. Que sont les alliages d'acier ?
  5. Que dois-je faire avec les données ? !
  6. Java - Structures de données
  7. Qu'est-ce que l'IIoT ?
  8. Qu'est-ce que les données de maintenance ?
  9. Comprendre le travail du bois