Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Industrial Internet of Things >> Eingebettet

Eingebettetes C verstehen:Was sind Strukturen?

Nach der Einführung von Strukturen werfen wir einen Blick auf einige der wichtigen Anwendungen dieses mächtigen Datenobjekts. Dann untersuchen wir die Syntax der Sprache C, um eine Struktur zu deklarieren. Schließlich stellen wir kurz die Anforderung zur Datenausrichtung vor. Wir werden sehen, dass wir möglicherweise die Größe einer Struktur reduzieren können, indem wir einfach die Reihenfolge ihrer Mitglieder ändern.

Dieser Artikel enthält einige grundlegende Informationen zu Strukturen in der eingebetteten C-Programmierung.

Nach der Einführung von Strukturen werfen wir einen Blick auf einige der wichtigen Anwendungen dieses mächtigen Datenobjekts. Dann untersuchen wir die Syntax der Sprache C, um eine Struktur zu deklarieren. Schließlich stellen wir kurz die Anforderung zur Datenausrichtung vor. Wir werden sehen, dass wir möglicherweise die Größe einer Struktur reduzieren können, indem wir einfach die Reihenfolge ihrer Mitglieder ändern.

Strukturen

Mehrere Variablen gleichen Typs, die logisch miteinander verbunden sind, können zu einem Array gruppiert werden. Die Arbeit an einer Gruppe anstelle einer Sammlung unabhängiger Variablen ermöglicht es uns, die Daten anzuordnen und bequemer zu verwenden. Zum Beispiel können wir das folgende Array definieren, um die letzten 50 Samples eines ADC zu speichern, der eine Spracheingabe digitalisiert:

uint16_t voice[50]; 

Beachten Sie, dass uint16_t ist ein vorzeichenloser Integer-Typ mit einer Breite von genau 16 Bit. Dies ist in der C-Standardbibliothek stdint.h defined definiert , das unabhängig von den Systemspezifikationen Datentypen einer bestimmten Bitlänge bereitstellt.

Arrays können verwendet werden, um mehrere Variablen desselben Datentyps zu gruppieren. Was ist, wenn es eine Verbindung zwischen Variablen von verschiedenen gibt? Datentypen? Können wir diese Variablen in unserem Programm als Gruppe behandeln? Angenommen, wir müssen die Abtastrate des ADC angeben, der die Stimme . generiert Array oben. Wir können eine Float-Variable definieren, um die Abtastrate zu speichern:

Float-Sample_Rate; 

Obwohl die Variablen Stimme und sample_rate miteinander verwandt sind, werden sie als zwei unabhängige Variablen definiert. Um diese beiden Variablen miteinander zu verknüpfen, können wir ein mächtiges Datenkonstrukt der Sprache C verwenden, das als Struktur bezeichnet wird. Strukturen ermöglichen es uns, verschiedene Datentypen zu gruppieren und als einzelnes Datenobjekt zu behandeln. Eine Struktur kann verschiedene Arten von Variablentypen enthalten, wie z. B. andere Strukturen, Zeiger auf Funktionen, Zeiger auf Strukturen usw. Für das Sprachbeispiel können wir die folgende Struktur verwenden:

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

In diesem Fall haben wir eine Struktur namens record das zwei verschiedene Member oder Felder hat:Das erste Member ist ein Array von uint16_t -Elemente, und der zweite Member ist eine Variable vom Typ float. Die Syntax beginnt mit dem Schlüsselwort struct . Das Wort nach dem Schlüsselwort struct ist ein optionaler Name, mit dem später auf die Struktur verwiesen wird. Wir werden im Rest des Artikels weitere Details zum Definieren und Verwenden von Strukturen besprechen.

Warum sind Strukturen wichtig?

Das obige Beispiel weist auf eine wichtige Anwendung von Strukturen hin, nämlich die Definition von anwendungsabhängigen Datenobjekten, die einzelne Variablen unterschiedlichen Typs miteinander verknüpfen können. Dies führt nicht nur zu einer effizienten Manipulation der Daten, sondern ermöglicht uns auch, spezialisierte Strukturen, sogenannte Datenstrukturen, zu implementieren.

Datenstrukturen können für verschiedene Anwendungen verwendet werden, z. B. für die Nachrichtenübermittlung zwischen zwei eingebetteten Systemen und das Speichern von von einem Sensor gesammelten Daten an nicht zusammenhängenden Speicherorten.

Abbildung 1. Strukturen können verwendet werden, um eine verknüpfte Liste zu implementieren.

Darüber hinaus sind Strukturen nützliche Datenobjekte, wenn das Programm auf die Register eines speicherabgebildeten Mikrocontroller-Peripheriegeräts zugreifen muss. Wir werden uns im nächsten Artikel die Strukturanwendungen ansehen.

Abbildung 2. Speicherbelegung einer STM32-MCU. Bild mit freundlicher Genehmigung von Embedded Systems mit ARM.

Eine Struktur deklarieren

Um Strukturen zu verwenden, müssen wir zunächst eine Strukturvorlage angeben. Betrachten Sie den folgenden Beispielcode:

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

Dies gibt ein Layout oder eine Vorlage zum Erstellen der zukünftigen Variablen dieses Typs an. Diese Vorlage enthält ein Array von uint16_t und eine Variable vom Typ float. Der Name der Vorlage ist record , und dies kommt nach dem Schlüsselwort struct . Es ist erwähnenswert, dass es keine Speicherzuweisung zum Speichern einer Strukturvorlage gibt. Die Speicherzuweisung erfolgt erst, nachdem eine auf diesem Layout basierende Strukturvariable definiert wurde. Der folgende Code deklariert die Variable mic1 der obigen Vorlage:

struct record mic1; 

Jetzt wird ein Speicherabschnitt für die Variable mic1 . zugewiesen . Es bietet Platz für die vier uint16_t Elemente des Arrays und eine Float-Variable.

Auf die Member einer Struktur kann mit dem Member-Operator (.) zugegriffen werden. Der folgende Code weist beispielsweise dem ersten Element des Arrays 100 zu und kopiert den Wert von sample_rate zum fs Variable (die vom Typ float sein muss).

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

Andere Möglichkeiten, eine Struktur zu deklarieren

Wir haben uns im vorherigen Abschnitt eine Möglichkeit zur Deklaration von Strukturen angesehen. Die Sprache C unterstützt einige andere Formate, die in diesem Abschnitt behandelt werden. Sie werden wahrscheinlich in Ihren Programmen bei einem Format bleiben, aber manchmal kann es hilfreich sein, mit den anderen vertraut zu sein.

Die allgemeine Syntax zum Deklarieren der Vorlage einer Struktur ist:

struct tag_name { type_1 Mitglied_1; Typ_2 Mitglied_2; … type_n member_n;} variable_name; 

Der tag_name und variable_name sind optionale Bezeichner. Normalerweise sehen wir mindestens einen dieser beiden Bezeichner, aber es gibt Fälle, in denen wir beide entfernen können.

Syntax 1: Wenn beide tag_name und variable_name vorhanden sind, definieren wir die Strukturvariable direkt nach der Vorlage. Mit dieser Syntax können wir das vorherige Beispiel wie folgt umschreiben:

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

Wenn wir nun eine andere Variable definieren müssen (mic2 ), können wir schreiben

struct record mic2; 

Syntax 2: Nur variable_name ist enthalten. Mit dieser Syntax können wir das Beispiel im vorherigen Abschnitt wie folgt umschreiben:

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

In diesem Fall müssen wir alle unsere Variablen direkt nach der Vorlage definieren und können später in unserem Programm keine anderen Variablen definieren (weil die Vorlage keinen Namen hat und wir später nicht darauf verweisen können).

Syntax 3: In diesem Fall gibt es keinen tag_name oder variable_name . Auf diese Weise definierte Strukturvorlagen werden als anonyme Strukturen bezeichnet. Eine anonyme Struktur kann innerhalb einer anderen Struktur oder Union definiert werden. Ein Beispiel ist unten angegeben:

struct test { // Anonyme Struktur struct { float f; Zeichen ein; };} test_var; 

Um auf die Member der oben genannten anonymen Struktur zuzugreifen, können wir den Member-Operator (.) verwenden. Der folgende Code weist dem Mitglied f 1.2 zu .

test_var.f=1.2; 

Da die Struktur anonym ist, greifen wir nur einmal auf ihre Member zu, indem wir den Member-Operator verwenden. Wenn es einen Namen wie im folgenden Beispiel hätte, müssten wir den Member-Operator zweimal verwenden:

struct test { struct { float f; Zeichen ein; } verschachtelt;} test_var; 

In diesem Fall sollten wir den folgenden Code verwenden, um f 1.2 1.2 zuzuweisen :

test_var.nested.f=1.2; 

Wie Sie sehen, können anonyme Strukturen den Code lesbarer und weniger ausführlich machen. Es ist auch möglich, das Schlüsselwort typedef zusammen mit einer Struktur zu verwenden, um einen neuen Datentyp zu definieren. Wir werden uns diese Methode in einem zukünftigen Artikel ansehen.

Speicherlayout für eine Struktur

Der C-Standard garantiert, dass die Member einer Struktur nacheinander in der Reihenfolge im Speicher abgelegt werden, in der die Member innerhalb der Struktur deklariert sind. Die Speicheradresse des ersten Members entspricht der Adresse der Struktur selbst. Betrachten Sie das folgende Beispiel:

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

Vier Speicherplätze werden zugewiesen, um die Variablen c, d, e und f zu speichern. Die Reihenfolge der Speicherorte entspricht der der Deklaration der Mitglieder:Der Speicherort für c hat die niedrigste Adresse, dann erscheinen d, e und schließlich f. Wie viele Bytes benötigen wir, um diese Struktur zu speichern? Angesichts der Größe der Variablen wissen wir, dass mindestens 1+4+1+2=8 Byte benötigt werden, um diese Struktur zu speichern. Wenn wir diesen Code jedoch für einen 32-Bit-Computer kompilieren, werden wir überraschenderweise feststellen, dass die Größe von MyStruct ist 12 Byte statt 8! Dies liegt daran, dass ein Compiler beim Zuweisen von Speicher für verschiedene Member einer Struktur bestimmte Einschränkungen hat. Beispielsweise kann eine 32-Bit-Ganzzahl nur an Speicherplätzen gespeichert werden, deren Adresse durch vier teilbar ist. Solche Beschränkungen, die als Datenausrichtungsanforderungen bezeichnet werden, werden implementiert, damit der Prozessor effizienter auf Variablen zugreifen kann. Die Datenausrichtung führt zu etwas verschwendetem Platz (oder Auffüllen) im Speicherlayout. Dieses Thema wird hier nur eingeführt; wir werden die Details im nächsten Artikel dieser Serie durchgehen.

Abbildung 3. Die Datenausrichtung führt zu etwas verschwendetem Speicherplatz (oder Auffüllen) im Speicherlayout.

Da wir uns der Anforderungen an die Datenausrichtung bewusst sind, können wir möglicherweise die Reihenfolge der Elemente innerhalb einer Struktur neu anordnen und die Speichernutzung effizienter gestalten. Wenn wir beispielsweise die obige Struktur wie unten angegeben umschreiben, verringert sich ihre Größe auf einem 32-Bit-Rechner auf 8 Byte.

struct Test2{ uint32_t d; uint16_t f; uint8_tc; uint8_t e;} MyStruct; 

Für ein eingebettetes System mit eingeschränktem Speicher ist es eine erhebliche Einsparung, die Größe eines Datenobjekts von 12 Byte auf 8 Byte zu reduzieren, insbesondere wenn ein Programm viele dieser Datenobjekte benötigt.

Im nächsten Artikel wird die Datenausrichtung ausführlicher erörtert und einige Beispiele für die Verwendung von Strukturen in eingebetteten Systemen untersucht.

Zusammenfassung

Um eine vollständige Liste meiner Artikel zu sehen, besuchen Sie bitte diese Seite.


Eingebettet

  1. Was sind feuerfeste Metalle?
  2. Was sind Deckschrauben?
  3. Was sind federunterstützte Dichtungen?
  4. Was sind Holzschrauben?
  5. Was sind Stahllegierungen?
  6. Was mache ich mit den Daten?!
  7. Java - Datenstrukturen
  8. Was ist IIoT?
  9. Was sind Wartungsdaten?
  10. Holzbearbeitung verstehen