Forum: Mikrocontroller und Digitale Elektronik Switch/Case auf Array anwenden


von Hansemann (Gast)


Lesenswert?

Hallo,

ich möchte als Switch-Variable ein Bitarray verwenden.

Je nach gesetztem Bit soll ein bestimmter case durchlaufen werden.

Jetzt stelle ich mir gerade die Frage ob das überhaupt funktioniert.

Danke fürs Interesse

von Heinz (Gast)


Lesenswert?

Hansemann schrieb:
> Danke fürs Interesse

Bitte.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Was soll ein "Bitarray" sein?

von Markus E. (engelmarkus)


Lesenswert?

Ja so vielleicht oder?
1
uint8_t variable = 0b00100000;
2
3
switch (variable) {
4
  case 0b00000001:
5
    break;
6
  case 0b00000010:
7
    break;
8
  // ...
9
}

Und was machst du jetzt wenn mehr als ein Bit gesetzt ist? Ist das deine 
Frage oder was? ;)

von Hansemann (Gast)


Lesenswert?

Hallo,

danke für die Antworten.

Was ein Bitarray sein soll geht glaube ich aus dem Namen hervor. Es ist 
ein Array vom Typ Bool. Bsp: bool arr[5];

Ich wollte wissen ob das überhaupt geht, oder ob switch() generell immer 
eine ganzzahlige Variable erwartet.

Danke

von Hansemann (Gast)


Lesenswert?

Hatte jetzt einen Compiler parat.

switchtest.cpp(12): error C2450: switch-Ausdruck des Typs 'bool [5]' 
nicht zulässig. Ganzzahliger Ausdruck erwartet.

Damit ist das geklärt.

von Dussel (Gast)


Lesenswert?

>Was ein Bitarray sein soll geht glaube ich aus dem Namen hervor.
>Es ist ein Array vom Typ Bool.

Nur der Vollständigkeit halber: Ein bool hat normalerweise nicht ein 
Bit. Da heißt, wenn du acht bool erstellst, brauchst du meistens nicht 
ein Byte, sondern acht Byte (bzw. genaugenommen word).

von Hansemann (Gast)


Lesenswert?

Sorry, aber diese Aussage zweifle ich jetzt mal stark an.

Ein Array vom Typ Bool mit beispielsweise 5 bit also z.B.

bool arr[5];

sollte nach meinem Versändnis auch genau 5 bit lang sein und nicht 
länger oder kürzer.

von Der Weise (Gast)


Lesenswert?

Nein, denn viele Prozessoren haben 8,16,32 oder gar 64 Bit-Register, 
aber keine 1-Bit-Register, können somit mit einzelnen Bits nicht 
umgehen. Gleiches gilt für den Arbeitsspeicher. Somit ist ein C++ - 
'bool' oft ein ganzes Byte, oder gar noch mehr.

von Stefan E. (sternst)


Lesenswert?

Hansemann schrieb:
> Sorry, aber diese Aussage zweifle ich jetzt mal stark an.
>
> Ein Array vom Typ Bool mit beispielsweise 5 bit also z.B.
>
> bool arr[5];
>
> sollte nach meinem Versändnis auch genau 5 bit lang sein und nicht
> länger oder kürzer.

Falsch gedacht. bool ist mindestens so groß wie char.

von Hansemann (Gast)


Lesenswert?

Praktisch ein Byte (oder mehr) das zweckentfremdet wurde ? Es kennt 
trotzdem nur die Zustände 0 oder 1 ?

Interessant. Das wußte ich wirklich noch nicht.

von Stefan E. (sternst)


Lesenswert?

Hansemann schrieb:
> Praktisch ein Byte (oder mehr) das zweckentfremdet wurde ? Es kennt
> trotzdem nur die Zustände 0 oder 1 ?

Richtig.

von Karl H. (kbuchegg)


Lesenswert?

Hansemann schrieb:
> Praktisch ein Byte (oder mehr) das zweckentfremdet wurde ? Es kennt
> trotzdem nur die Zustände 0 oder 1 ?
>
> Interessant. Das wußte ich wirklich noch nicht.

Dann merk dir.
Das kleinste was es in C gibt, ist ein char. Definitionsgemäss hat ein 
char eine sizeof von 1. Kleiner als 1 geht nicht.

von Der Weise (Gast)


Lesenswert?

Hansemann schrieb:
> Es kennt
> trotzdem nur die Zustände 0 oder 1 ?
Nein, man kann im Prinzip alle Zustände zuweisen, aber der Compiler 
verwendet eben nur true als '1' und false als '0'. Alles != 0 wird aber 
von if () als wahr erkannt. In C gibt es gar kein 'bool', nur 'char', 
und das ist eben ein byte, welchem man zB 0 und 1 zuweist. C++ kann da 
nicht 'mehr', es sieht nur hübscher aus mit 'bool'.

von Stefan E. (sternst)


Lesenswert?

Der Weise schrieb:
> Hansemann schrieb:
>> Es kennt
>> trotzdem nur die Zustände 0 oder 1 ?
> Nein, man kann im Prinzip alle Zustände zuweisen,

Doch. Du kannst zwar auch 42 zuweisen, aber in der Variable steht danach 
1. Die Variable selber kennt also nur 0 und 1.

Der Weise schrieb:
> In C gibt es gar kein 'bool'

Das stimmt schon seit einigen Jahren nicht mehr. Es gibt in stdbool.h 
ein bool als Alias für den integralen Typ _Bool, der auch obige 
Eigenschaft hat.

von Hansemann (Gast)


Lesenswert?

Das kann ich bestätigen. Ich benutze einen ANSI-C Compiler und dieser 
kennt definitiv den Typ Bool.

von Uli T. (avaron)


Lesenswert?

bool hat generell die länge eines char! Allerdings kannst Du ein 
sogenanntes Bitset verwenden.....  Der Speicherbedarf davon ergibts sich 
dann bei den meisten Compilern als (Bitanzahl)/8 Byte.

von Martin (Gast)


Lesenswert?

Hier gabs einige Halbwahrheiten als Antwort. Diese stimmen zwar für die 
meisten C Implementierungen, aber eben nicht für alle.

Bei solchen Fragen ist es meist am einfachsten, wenn man sich den 
C-Standard ansieht. Und zwar den, den man zur Programmierung verwendet. 
Ich kenne Firmen, bei denen wird noch nach C90 entwickelt. Da sind z.B. 
nicht mal Kommentare erlaubt, welche mit // beginnen, nur /* */.
_Bool gibts ab C99.

Bei Datentypen gibt der C-Standard der Compilerimplementierung einen 
relativ großen Spielraum. Kein Datentyp ist fix definiert, sondern gibt 
einen minimale Kapazität bzw. Bereich vor (C99 Kapitel 5.2.4.2.1 Sizes 
of integer types).
z.B. C99 Kapitel 6.2.5: An object declared as _Bool is large enough to 
store the values 0 and 1.
Was der Compiler daraus macht, ist nun seine Sache.
Es gibt (wenige) Prozessoren, welche einen bitadressierbaren 
Speicherbereich haben. Für diese bietet es sich natürlich an, diesen zu 
verwenden.
Der Compiler könnte aber auch Bitoperatoren auf einem _Bool verwenden, 
um die Daten effizient zu speichern. Natürlich auf Kosten der Laufzeit.
Die meisten C-Implementierungen werden aber, wie hier erwähnt, einfach 
jeweils ein Byte verwenden. Aber auch hier kenne ich 
Projektkonfigurationen, bei denen 32 Bit für einen _Bool verwendet 
werden (Ich versteh auch nicht warum).

Der Aussage, daß wenn man einer _Bool Variablen eine 42 zuweist, eine 1 
rauskommt, hätte ich erstmal widersprochen. Da lag ich aber falsch, die 
Aussage stimmt.
C99 6.3.1.2 Boolean type
When any scalar value is converted to _Bool, the result is 0 if the 
value compares equal to 0; otherwise, the result is 1.

Auch wenn es sich so anhört, eigentlich wollte ich nicht klugscheißen. 
Ich habe einfach festgestellt, daß man stundenlang über das Verhalten 
eines C-Compilers diskutieren kann, aber nur im C-Standard steht, wie es 
sein sollte.
Ich lag auch schon häufig falsch, obwohl ich mir sicher war. Nach langer 
Diskussion musste ich oft, nach einem Blick in den C-Standard, klein 
beigeben.

von Uli T. (avaron)


Lesenswert?

Ansonsten findest Du hier die Grammatik von C++ (ist für Deine Frage zu 
C nahezu identisch)

http://www2.math.uni-wuppertal.de/~axel/skripte/oop/oopA.html

=> sowie Du Dir das vorstellst funktioniert es nicht.

Du kannst bools allerdings sehr wohl platzsparend packen, und zwar mit 
einem Bit Field (sorry das ich oben irgendwo aus gewohnheit den Begriff 
Bit field verwendet habe)....


Struct BlaBla {
  bool blabla1 : 1;
  bool blabla2 : 1;
}

etc....

Kannst Du auch über meherer Bits aufziehen, also z.B.

struct IOAddr {
  bool IO : 1;
  int addr : 15;
}

das ganze noch in ne union gepackt kann man wunderbar die bits 
strukturell benamt rausziehen....

In

http://www.9wy.net/onlinebook/CPrimerPlus5/ch15lev1sec4.html

findest Du ein wunderbares beispiel wie man Bitfields in 
switch-Statements verwendet....

Hoffe das hilft!

von Uli T. (avaron)


Lesenswert?

> Auch wenn es sich so anhört, eigentlich wollte ich nicht klugscheißen.
> Ich habe einfach festgestellt, daß man stundenlang über das Verhalten
> eines C-Compilers diskutieren kann, aber nur im C-Standard steht, wie es
> sein sollte.
> Ich lag auch schon häufig falsch, obwohl ich mir sicher war. Nach langer
> Diskussion musste ich oft, nach einem Blick in den C-Standard, klein
> beigeben.

Daran ist nichts überheblich... Und viele Sachen sind wie beispielsweise 
dangling else einfach nicht alle compilerimplementierungen gleich.... 
Und sowohl C'90 als auch C'99 sind nicht immer 100%ig umgesetzt in den 
einzelnen Compilern... Schlimmer wirds nur noch bei verwendung von 
C++... Wer hätte erwartet das:

If (a && (a->b == 1) { ....

völlig unterschiedlich abgearbeitet wird wenn der ||-operator überladen 
wird...

Klar, ein Blick in die zugrundeliegenden Mechanismen macht eindeutig was 
passiert, aber aufs erste lesen kommt man nicht drauf....

Nicht überladen:

a == NULL => Ergebniss steht fest => a->b == 1 wird nicht ausgewertet.

Überladen:

a && xx wird durch 2 Funktionsaufrufe ersetzt => Beide Statements werden 
abgearbeitet... Und a->b wird wenn a == NULL zum Problem....

von Martin (Gast)


Lesenswert?

Ein Struct Bitfield in Kombination mit einer Union würde ich in C nicht 
empfehlen! Wenn man MISRA beachten, dann ists auch nicht erlaubt.
Gerade hier gibt es sehr viele Umsetzungsunterschiede (welche der 
C-Standard erlaubt).
Wie genau die Daten einer Struct im Speicher abgelegt werden, ist nicht 
eindeutig festgelegt. Da legen die Compiler gerne Füllbytes rein. 
Stichwort Padding.


Ich bin leider gar nicht auf die ursprüngliche Frage eingegangen. Aber 
was soll im in diesem Switch Case passieren?
Sollten unterschiedliche Reaktionen pro boolschem Wert passieren, also

A)
Wenn Bool_1 dann führe Code_1 aus
Wenn Bool_2 dann führe Code_2 aus
Wenn Bool_1 und Bool_2 dann führe Code_1 und Code_2 aus

oder mit Kombinationen, also

B)
Wenn Bool_1 dann führe Code_1 aus
Wenn Bool_2 dann führe Code_2 aus
Wenn Bool_1 und Bool_2 dann führe Code_3 aus

Für A) wäre ein Switch Case eher nicht geeignet.
Für B) könnte man ggf. ein Lösung finden

von Martin (Gast)


Lesenswert?

Danke Uli.

Mit dem C-Standard bin ich mittlerweile sehr vertraut.
Aber ich muß zugeben, mit C++ kenn ich mich so gut wie gar nicht aus.

von Stefan E. (sternst)


Lesenswert?

Martin schrieb:
> Bei Datentypen gibt der C-Standard der Compilerimplementierung einen
> relativ großen Spielraum. Kein Datentyp ist fix definiert, sondern gibt
> einen minimale Kapazität bzw. Bereich vor (C99 Kapitel 5.2.4.2.1 Sizes
> of integer types).
> z.B. C99 Kapitel 6.2.5: An object declared as _Bool is large enough to
> store the values 0 and 1.
> Was der Compiler daraus macht, ist nun seine Sache.
> Es gibt (wenige) Prozessoren, welche einen bitadressierbaren
> Speicherbereich haben. Für diese bietet es sich natürlich an, diesen zu
> verwenden.

Und was soll sizeof(_Bool) in dem Fall sein?

Martin schrieb:
> Der Compiler könnte aber auch Bitoperatoren auf einem _Bool verwenden,
> um die Daten effizient zu speichern. Natürlich auf Kosten der Laufzeit.

Und wie sieht dann ein Pointer auf _Bool aus?

Es gibt eben halt noch ein paar mehr Dinge zu bedenken, als nur "large 
enough to store the values 0 and 1".

Martin schrieb:
> Aber auch hier kenne ich
> Projektkonfigurationen, bei denen 32 Bit für einen _Bool verwendet
> werden (Ich versteh auch nicht warum).

Wie viel Bit hat ein char dort?
sizeof(char) ist immer 1, egal wie viel Bit es hat. Und kleiner als 1 
geht nun mal nicht, also ist auch ein _Bool immer mindestens so groß wie 
ein char.

von Christian G. (christian_g83)


Lesenswert?

Stefan Ernst schrieb:

> Wie viel Bit hat ein char dort?

Das hängt von der Prozessorarchitektur ab. Laut Standard ist ein char 
immer ein Byte groß. Wieviel Bits jetzt in einem Byte stecken, ist 
architekturabhängig. Der Standard sagt lediglich, dass es mindestens 
acht sein müssen.

Christian

von Karl H. (kbuchegg)


Lesenswert?

Christian Gudrian schrieb:
> Stefan Ernst schrieb:
>
>> Wie viel Bit hat ein char dort?
>
> Das hängt von der Prozessorarchitektur ab. Laut Standard ist ein char
> immer ein Byte groß.

Vorsicht, der C-Standard versteht unter einem 'Byte' etwas anderes als 
ein Computerarchitekt. Für den C-Standard ist ein Byte die kleinste 
adressierbare Speichereinheit. Und wenn dieses Byte aus 16 Bit besteht, 
dann ist das im Sinne des C-Standards ein Byte. Für jemanden aber der 
sich mit Speicherbausteinen rumschlägt sind das 2 Byte.
Ob dieser Unterscheidung kommen regelmässig Missverständnisse zu Stande.

von Vlad T. (vlad_tepesch)


Lesenswert?

Uli Trautenberg schrieb:
> bool hat generell die länge eines char!

das ist falsch

Martin schrieb:
> Aber auch hier kenne ich
> Projektkonfigurationen, bei denen 32 Bit für einen _Bool verwendet
> werden (Ich versteh auch nicht warum).

Manche Processoren können nur vielfache ihrer natürloichen Wortbreite 
adressieren.
dh. wenn diese 4 ist und du ein uint8_t hast, besteht ein Zugriff auf 
dieses uint8 immer darin, eine 32bit Variable auszulesen und den Rest 
auszumaskieren. was also mindestens immer 2 Befehle sind. wahrscheinlich 
kommt das Laden der Bitmaske und das zurechtschieben aber auch noch 
jeweils dazu.

ein uint8_t i[16] braucht nur 4 Wörter, aber die Zugriffe auf i[0]-i[3] 
resultieren im Auslesen der selben Adresse und zurechtmaskieren und 
shiften.

von Uli T. (avaron)


Lesenswert?

Vlad Tepesch schrieb:
> Uli Trautenberg schrieb:
>> bool hat generell die länge eines char!
>
> das ist falsch
>

Das ist leider richtig! Wollte schreiben: In der Praxis mindestens die 
größe eines chars und auf allen mir bekannten Implementierungen die 
größe der kleinsten adressierbaren Einheit (meistens 1 Byte)

von Martin (Gast)


Lesenswert?

Stefan Ernst schrieb:
> Martin schrieb:
>> Bei Datentypen gibt der C-Standard der Compilerimplementierung einen
>> relativ großen Spielraum. Kein Datentyp ist fix definiert, sondern gibt
>> einen minimale Kapazität bzw. Bereich vor (C99 Kapitel 5.2.4.2.1 Sizes
>> of integer types).
>> z.B. C99 Kapitel 6.2.5: An object declared as _Bool is large enough to
>> store the values 0 and 1.
>> Was der Compiler daraus macht, ist nun seine Sache.
>> Es gibt (wenige) Prozessoren, welche einen bitadressierbaren
>> Speicherbereich haben. Für diese bietet es sich natürlich an, diesen zu
>> verwenden.
>
> Und was soll sizeof(_Bool) in dem Fall sein?
>
Dazu gibt der C-Standard nichts her. _Bool ist im C99 doch wirklich 
reingepriemelt. Wie in allen solchen Fällen führt dies zu einem 
"implementation definied behaviour". Gibts an mehreren Stellen. Bei 
sizeof ist dies sogar explizit erwähnt (C99 6.5.3.4 The value of the 
result is implementation-defined, and its type...). Dazu muß man dann 
das entsprechende Compilerhandbuch zur Hand nehmen.

In dem Fall, der bitadressierbaren Speicherbereich sollte es gar nicht 
so schwer sein. Soweit ich weiß, verwenden diese Prozessoren für jedes 
Bit in diesem Speicherbereich eine eigene Adresse. Wobei allerdings an 
dieser Adresse wirklich nur ein Bit Speicherplatz zur Verfügung steht! 
Somit könnte man bei sizeof 1 zurückgeben und die weiteren Bedingungen 
an sizeof wären erfüllt. Vor allem sizeof(array) / sizeof(array[0]).

Meine andere Aussage, daß der Compiler Bitoperatoren verwenden darf, um 
einen _Bool zu speichern, muß ich zurücknehmen. Damit kann man die 
sizeof Anforderungen nicht erfüllen.

Wobei ich annehme, daß es für den Fall der bitadressierbaren 
Speicherbereiche, wirklich Umsetzungen gibt, für den zweiten nicht.

> Martin schrieb:
>> Der Compiler könnte aber auch Bitoperatoren auf einem _Bool verwenden,
>> um die Daten effizient zu speichern. Natürlich auf Kosten der Laufzeit.
>
> Und wie sieht dann ein Pointer auf _Bool aus?
>
> Es gibt eben halt noch ein paar mehr Dinge zu bedenken, als nur "large
> enough to store the values 0 and 1".
>

Wie schon erwähnt, da habe ich erst geschrieben, dann gedacht.
Trotzdem kann ein _Bool kleiner sein als 8 Bit.

> Martin schrieb:
>> Aber auch hier kenne ich
>> Projektkonfigurationen, bei denen 32 Bit für einen _Bool verwendet
>> werden (Ich versteh auch nicht warum).
>
> Wie viel Bit hat ein char dort?
> sizeof(char) ist immer 1, egal wie viel Bit es hat. Und kleiner als 1
> geht nun mal nicht, also ist auch ein _Bool immer mindestens so groß wie
> ein char.


Ein Char hat 1 Byte, 8 Bit. Bei Prozessoren mit bitadressierbieren 
Speicher (z.B. 8051  80515  80535 - hab aber persönlich keine 
Erfahrung damit) kann aber ein _Bool kleiner sein. Aber dort hat eben 
wirklich jedes Bit eine eigene Adresse.

Der Aussage _Bool ist immer mindestens so groß wie ein char muß ich 
damit wirklich wiedersprechen. Sizeof kann natürlich minimal 1 
zurückgeben. Es kommt halt noch aus Zeiten, in denen es in C noch kein 
_Bool gab. Aber im Speicher kann ein _Bool wirklich auch nur ein Bit 
sein (entsprechender Prozessor vorausgesetzt).

Bei dem Projekt mit den 32bit _Bool liefert sizeof natürlich 4 zurück. 
Die Idee dahinter war, die native Speichergröße des 32bit-Prozessors für 
ein _Bool zu verwenden. Der Prozessor kann mit diesen nativen Variablen 
meist am effektivsten umgehen (darum bietet sich z.B. für eine 
Schleifenvariable int an). Im Fall von _Bool bezweifle ich aber, daß es 
dort effektiver wird.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Zurück zur eigentlichen Frage:

Nein, switch/case lassen sich nur auf ganzzahlige Datentypen anwenden. 
Nicht auf Arrays, nicht auf floatingpoint-Werte und auch nicht auf 
Strings (die ja auch nur Arrays sind).

von Christian G. (christian_g83)


Lesenswert?

Karl Heinz Buchegger schrieb:

> Ob dieser Unterscheidung kommen regelmässig Missverständnisse zu Stande.

Und deshalb danke ich Dir für die explizite Klarstellung.

Und der Vollständigkeit halber: die korrekte, unmissverständliche 
Bezeichnung für eine Gruppe von acht Bits lautet "Oktett".

Christian

von Christian G. (christian_g83)


Lesenswert?

Martin schrieb:

> Ein Char hat 1 Byte, 8 Bit.

Mindestens 8 Bit. Es können mehr sein, auch wenn einem das in der 
Realität nur selten begegnet.

Christian

von Martin (Gast)


Lesenswert?

Christian Gudrian schrieb:
> Martin schrieb:
>
>> Ein Char hat 1 Byte, 8 Bit.
>
> Mindestens 8 Bit. Es können mehr sein, auch wenn einem das in der
> Realität nur selten begegnet.
>
> Christian

Stimmt natürlich!

von Uwe (Gast)


Lesenswert?

Man kann switch aber auf einzelne Elemente des Arays anwenden und die 
switch Anweisung dann verschachteln.

char b[5];

switch(b[0])
{
case 0:
  switch(b[1])
    {
    case 1:
      switch(b[2])
        {
        case 0b00010100 :
        break;
        case 0b00010101 :
        break;
        }
    break;
    case 2:
      switch(b[2])
        {
        case 0b00010100 :
        break;
        case 0b00010101 :
        break;
        }
    break;
    }
break;
case 1:
  switch(b[1])
    {
    case 3:
      switch(b[2])
        {
        case 0b00010100 :
        break;
        case 0b00010101 :
        break;
        }
    break;
    case 9:
      switch(b[2])
        {
        case 0b00010100 :
        break;
        case 0b00010101 :
        break;
        }
    break;
    }
break;

}

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Uwe schrieb:
> Man kann switch aber auf einzelne Elemente des Arays anwenden

Vorausgesetzt, daß diese Elemente wiederum ganzzahlige Datentypen 
sind.

Im übrigen ist die binäre Schreibweise mit 0b-Präfix nicht im 
C-Standard enthalten. So etwas ist eine proprietäre Compilererweiterung 
und man sollte sich den Gebrauch schleunigstens wieder abgewöhnen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.