Ich habe zwei Variablen definiert:
uint8_t a[2];
uint16_t b;
Als nächstes möchte ich a
als Variable vom Typ verwenden uint16_t
, z
b = (uint16_t)a;
Das ist aber falsch! Meine Programme funktionieren mit solchem Code nicht richtig. Alles ist in Ordnung , wenn ich ersetzen b
zu uint8_t b[2]
und die Nutzung element Operationen.
Warum?
Antworten:
a
ist ein Zeiger auf ein Array von Bytes. Wenn Sie es in ein uint16_t umwandeln und es zuweisenb
,b
enthält es die Adresse der Basis des Arrays (wo es gespeichert ist) im SRAM. Wenn Sie die beiden Bytes des Arraysa
als Ganzzahl behandeln möchten , verwenden Sie eine Union, wie von user14284 vorgeschlagen. Beachten Sie jedoch, dass die Union das Byte-Array in der Reihenfolge der Speicherbytes der Architektur darstellt (in AVR wäre das wenig -endian, was bedeutet, dass Byte 0 das niedrigstwertige Byte ist). Der Weg, dies in Code zu schreiben, ist:Eine andere Möglichkeit, dies ohne Verwendung einer Union zu tun, besteht darin,
a
in einen uint16_t-Zeiger umzuwandeln und ihn dann wie folgt zu dereferenzieren:Wenn Sie den Puffer zum Speichern von Big-Endian-Daten verwenden (z. B. Netzwerkbyte-Reihenfolge), müssen Sie einen Byte-Swap durchführen, um eine dieser Techniken zu verwenden. Eine Möglichkeit, dies ohne Verzweigungen oder temporäre Variablen zu tun, ist:
Dies ist übrigens kein AVR- oder sogar ein Embedded-Only-Problem. Application - Level - Netzwerk - Code für PCs geschrieben typischerweise Anrufe Funktionen genannt
htonl
,htons
(Host - Netzwerk, 32- und 16-Bit - Varianten) undntohl
,ntohs
(Netzwerk - Host, 32- und 16-Bit - Varianten) , deren Implementierungen sind Zielarchitektur abhängig, ob sie Tauschen Sie die Bytes aus oder nicht (unter der Annahme, dass die auf der Leitung übertragenen Bytes immer Big-Endian sind, wenn sie Teil von Mehrbyte-Wörtern sind).quelle
a
für sich allein ist, ist ein Zeiger.-fno-strict-aliasing
.Wenn Sie die beiden 8-Bit-Variablen zu einer 16-Bit-Variablen verketten möchten, verwenden Sie a
union
. Wenn Sie ein einzelnes Mitglied vona
inb
umwandeln möchten, geben Sie an, welches Element des Arrays Sie verwenden möchten.quelle
In Ihrem Code setzen Sie nur den Zeiger auf das Array.
Sie müssen den Wert, auf den gezeigt wird, umwandeln
a
.Ich habe AVR nie verwendet, aber wenn Sie mit einer 16-Bit-Architektur arbeiten, müssen Sie sicherstellen, dass a wortausgerichtet ist. Andernfalls kann es zu einer Ausnahme kommen.
quelle
Jedes Mitglied von a ist eine 8-Bit-Nummer. Es kann nichts Größeres halten. Das Casting auf 16 Bit hat nichts mit a zu tun . Es extrahiert lediglich den Wert, den a möglicherweise halten kann, und konvertiert ihn in 16 Bit, sodass er mit dem Format von b übereinstimmt, wenn der Wert dort gespeichert wird.
Sie haben sich nicht einmal auf ein Mitglied von a bezogen . Sie müssen eine [0] oder eine [1] verwenden (und keine [2]!). Wenn Sie eine für sich verwenden, erhalten Sie nur die Adresse. (Guter Fang, Bruno).
Wenn Sie a als Array aus zwei 8-Bit-Zahlen deklarieren, wird es auch nicht zu einer 16-Bit-Zahl. Sie können einige Dinge programmgesteuert ausführen, um 16-Bit-Werte mithilfe von 8-Bit-Sequenzen zu speichern und abzurufen, aber nicht so, wie Sie es sich vorgestellt haben.
quelle
Wenn Sie die Bytes
a
in einen 16-Bit-Wert konvertieren möchten und die Darstellung Little-Endian ist (die unteren 8 Bits des Werts kommen im ersten Byte), tun Sie diesFür eine Big-Endian-Darstellung tun
Vermeiden Sie dazu Zeiger-Casts oder Gewerkschaften, da dies zu Portabilitätsproblemen führt.
quelle