Array into int und dann Bit Verschiebung

Gast #3889839
Lesenswert?

Guten Morgen,

vermutlich sehr einfache Frage.
Ich habe folgendes Array:

unsigned char Array[3];

Jetzt möchte ich gerne das letzte Bit rausschieben.
Array = Array >> 1 funktioniert natürlich nicht.

Am allerliebsten würde ich die drei Array Elemente als eine Zahl in 
einem int abspeicher, also Array[0] = High Byte, Array[1] = MittelByte, 
Array[2] = Low Byte,

Dann könnte ich das letzte Bit auch einfach rausscheiben.

Wie macht man sowas?
#3889844
Lesenswert?

Spezi schrieb:
> Guten Morgen,
>
> vermutlich sehr einfache Frage.
> Ich habe folgendes Array:
>
> unsigned char Array[3];
>
> Jetzt möchte ich gerne das letzte Bit rausschieben.
> Array = Array >> 1 funktioniert natürlich nicht.
>
> Am allerliebsten würde ich die drei Array Elemente als eine Zahl in
> einem int abspeicher, also Array[0] = High Byte, Array[1] = MittelByte,
> Array[2] = Low Byte,
>
> Dann könnte ich das letzte Bit auch einfach rausscheiben.
>
> Wie macht man sowas?

Entweder in dem man im Array schiebt
1
uint8_t Carry1, Carry2;
2

3
   Carry1 = Array[2] & 0x01;
4
   Array[2] >>= 1;
5

6
   Carry2 = Array[1] & 0x01;
7
   Array[1] >>= 1
8
   if( Carry1 )
9
     Array[2] |= 0x80
10

11
   Array[0] >>= 1;
12
   if( Carry1 )
13
     Array[0] |= 0x80;

oder den Compiler machen lassen, so wie du das vorgeschlagen hast.
1
  union convert
2
  {
3
    uint8_t  Bytes[4];
4
    uint32_t Value;
5
  } convertVar;
6

7
  convertVar.Bytes[0] = Array[0];
8
  convertVar.Bytes[1] = Array[1];
9
  convertVar.Bytes[2] = Array[2];
10
  convertVar.Bytes[3] = 0;
11

12
  covertVar.Value >>= 1;
13

14
  Array[0] = convertVar.Bytes[0];
15
  ....

eine andere Möglichkeit, bei der man nicht umkopiert
1
  uint32_t * pValue;
2

3
  pValue = (uint32_t*)Array;
4
  *pValue >>= 1;

bei der Union Lösung hat man den Vorteil, dass man während des 
Umkopierens gleich die Bytereihenfolge für einen unsigned long 
entsprechend den Vorstellungen des COmpilers und/oder Systems anpassen 
kann, falls das notwendig ist. Bei der Pointer Variante muss man mit dem 
leben, wie sich der Compiler die Anordnung eines 32 Bit Wertes im 
Speicher so vorstellt.

Oder aber: man findet einen Weg, wie man sich das ganze Bitgeschubse 
sparen kann. Normalerweise ist das der beste Ansatz.
#3889854
Lesenswert?

Du könntest eine union verwenden:
1
typedef union _Zahl_def{
2
 UCHAR  Array[4];
3
 UINT32 Wert;
4
} Zahl_def;
5

6
Zahl_def Zahl;
7

8
Zahl.Array[0] = LowByte;
9
Zahl.Array[1] = MittelByte;
10
Zahl.Array[2] = HighByte;
11
Zahl.Array[3] = 0;
12

13
Zahl.Wert = Zahl.Wert >> 1;

Das ist jetzt aber ungeprüft.

Edit: Da war einer schneller...
Gast #3889910
Lesenswert?

Vielen Dank schon einmal für die ausführlichen freundlichen Antworten:
DIe Union Methode würde mich am Meisten interessieren:

Bis
convertVar.Bytes[0] = Array[0];
convertVar.Bytes[1] = Array[1];
convertVar.Bytes[2] = Array[2];
convertVar.Bytes[3] = 0;

ist auch alles klar.

Was genau macht er jetzt bei covertVar.Value >>= 1; ??? Klar shiftet er 
hier das Bit.
In meiner Anwendung soll in Value doch nur 24 Bit stehen.
Es müßte also in etwa wie folgt aussehen:
1
 union convert
2
  {
3
    uint8_t  Bytes[3];
4
    uint32_t Value;
5
  } convertVar;
6

7
  convertVar.Bytes[0] = Array[0];
8
  convertVar.Bytes[1] = Array[1];
9
  convertVar.Bytes[2] = Array[2];
10

11
  covertVar.Value >>= 1;

In Value stehen jetzt leider (verständlicherweise) nicht wie gewünscht 
die 24 Bit.
#3889961
Lesenswert?

Spezi schrieb:
> OK ich muss einfach die 8 Nullen nochmal rausshiften

?
Du musst da nichts rausshiften.
Du schreibst 3 Bytes in die union (und initialisierst das 4.te mit 0) 
und holst dir 3 Bytes aus der union.

Das in der union das Array 4 Bytes gross ist, hängt damit zusammen, dass 
auch ein uint32_t 4 Bytes gross ist und wir auch die Kontrolle über 
dieses 4.te Byte haben wollen. Und sei es nur, um es 0 zu setzen.

Was natürlich sein kann: dass die Bytereihenfolge des Arrays nicht mit 
der in einem uint32_t übereinstimmt. Das muss man dann eben 
ausprobieren, wie rum ein uint32_t im Speicher angeordnet ist.
#3889970
Lesenswert?

Spezi schrieb:

> In meiner Anwendung soll in Value doch nur 24 Bit stehen.

Es gibt aber auf dem AVR keinen Standard Datentyp mit 24 Bit. Der nächst 
größere hat 32 Bit. Wenn du also dem Compiler die Arbeit aufbürden 
willst, das byteübergreifende Schieben für dich zu erledigen, dann wirst 
du dich wohl oder übel nach dem richten müssen, was du hast. Und nicht 
nach dem, was du gerne hättest.

> Es müßte also in etwa wie folgt aussehen:
>
>
1
>  union convert
2
>   {
3
>     uint8_t  Bytes[3];
4
>     uint32_t Value;
5
>   } convertVar;
6
> 
7
>   convertVar.Bytes[0] = Array[0];
8
>   convertVar.Bytes[1] = Array[1];
9
>   convertVar.Bytes[2] = Array[2];
10
> 
11
>   covertVar.Value >>= 1;
12
>

Frage: welchen Wert hat das Bit, welches von links (von seiten des MSB) 
reinkommt?

Eben. Du hast da erst mal keine Kontrolle drüber.
Daher: das Array 4 Bytes gross machen und dieses 4.te Byte (aus dem das 
1 Bit nachgeschoben wird) auf 0 setzen.
Gast #3889994
Lesenswert?

Vielen Dank nochmal,

es gilt also einfach die Reihenfolge zu überprüfen.
Ich habe es jetzt fälschlicherweise wie folgt angeordnet:

HB | MB | LB | 0

habe dann 1 Bit geshiftet und dann nochmal 8 Bit für die 0, was 
natürlich quatsch ist , wenn ich von Anfang an wie folgt anordne: 0 | HB 
| MB | LB

Danke nochmals für die Hilfe.

Was mich mal interessieren würde Herr Buchegg, machen Sie das ganze hier 
eientlich "vollberuflich"?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren