mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Byte-Vektor aus Array extrahieren


Autor: Martin Kohler (mkohler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
Ich habe ein Array mit 8 Werten, z.B.:
BYTE value[8] = { 2, 5, 0, 0, 1, 7, 3, 0 };

Aus diesem Array möchte ich nun einen Byte-Vektor generieren, für 
welchen gilt:
- Bit0 ist 0 wenn value[0] = 0, sonst 1
- ...
- Bit7 ist 0 wenn value[7] = 0, sonst 1

Ich möchte also im Vektor anzeigen, ob die Array-Elemente 0 sind oder 
nicht.

Wie codiere ich das am effizientesten in C?

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das könnte funktionieren (ohne Gewähr und ungetestet):
uint8_t vector = 0;
for(int8_t i=7; i>=0; i++)
{
    vector |= value[i] && 1;
    vector <<= 1;
}
In "vector" sollte dann das stehen, was Du oben haben wolltest.

Autor: Niels Hüsken (monarch35)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johannes M. wrote:
>
>     vector |= value[i] && 1;
> 

Nein, das stimmt nicht. Das prüft nur das LSB in value[x].
Es müsste
 vector|= (value[i]?1:0); 

heissen. Auch sollte zuerst geshifted werden, sonst ist das vector-LSB 
immer low....

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Niels Hüsken wrote:
> Johannes M. wrote:
>>
>>     vector |= value[i] && 1;
>> 
>
> Nein, das stimmt nicht. Das prüft nur das LSB in value[x].
> Es müsste

Nein, das stimmt nicht. Es überprüft ob i!=0 (Also logisch wahr ist). 
Falls ja, evaluiert der Ausdruck zu "1" ansonsten zu "0".

>
>  vector|= (value[i]?1:0);
> 

Das macht das Gleiche (oder das Selbe? ;))

Autor: Martin Kohler (mkohler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Simon K. wrote:
> Falls ja, evaluiert der Ausdruck zu "1" ansonsten zu "0".

Der Ausdruck evaluiert zu nicht 0, richtig?
Obs eine 1 oder sonst was wird, ist doch compilerabhängig?

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Simon K. wrote:
> Nein, das stimmt nicht. Es überprüft ob i!=0 (Also logisch wahr ist).
> Falls ja, evaluiert der Ausdruck zu "1" ansonsten zu "0".
Genau so war es gedacht...

>>
>>  vector|= (value[i]?1:0);
>> 
>
> Das macht das Gleiche (oder das Selbe? ;))
Im Prinzip ja. Und was der Compiler draus macht, dürfte auch ungefähr 
auf das selbe hinauslaufen...

Man muss nur dafür sorgen (wie auch immer), dass aus dem Wert in 
value[i] ein Wahrheitswert wird. Und der kann nunmal nur 0 oder 1 sein.

@Niels:
Du verwechselst "&&" mit "&"! Das was Du meinst, ist "&", das steht aber 
nicht da...

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Martin Kohler wrote:
> Der Ausdruck evaluiert zu nicht 0, richtig?
Und "nicht 0" ist in C standardmäßig "1" (als Ausgabewert).

> Obs eine 1 oder sonst was wird, ist doch compilerabhängig?
Nö. ANSI sagt, dass das Ergebnis einer logischen Verknüpfung 0 oder 1 
ist. Als *Eingabe*-Wert stimmt Deine Annahme, dass alles, was nicht 0 
ist, als "true" interpretiert wird. Aber auch nur da.

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rein theoretisch müsste auch
vector |= !(!(value[i]));

Gehen. Es gibt bestimmt was kürzeres, aber da müsste dann mal einer der 
Profis ran ;)

Autor: Kai G. (runtimeterror)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
C ist jetzt nicht so meine Domäne, aber:
uint8_t vector = 0;
for(int8_t i=7; i>=0; i++)
{
    vector |= value[i] && 1;
    vector <<= 1;
}

bewirkt, dass das Endergebnis eins zu weit nach links geshiftet wird.

&& ist doch nur für booleans oder? Wenn C eh implizite Typecasts zulässt 
sollte Folgendes gehen:
uint8_t vector = 0;
for(int8_t i = 7; i >= 0; i++)
{
    vector = (value[i] << 1) | (value[i] != 0);
}

oder?

Autor: Niels Hüsken (monarch35)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Simon K. wrote:
> Nein, das stimmt nicht. Es überprüft ob i!=0 (Also logisch wahr ist).

F*ck! Sorry..hab das doppelte "&&" überlesen...mir war, da wäre nur ein 
einfaches "&". Naja, wer Augen hat wie ein Maulwurf.....

> Falls ja, evaluiert der Ausdruck zu "1" ansonsten zu "0".

Das Logisch True "1" ergibt, ist Compiler/ Platform abhängig. Wenn der 
AVR-GCC das so macht, ist das OK, ist aber nicht standardisiert, soweit 
ich weiss.

IMO wäre die x?1:0 Lösung vorzuziehen.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kai Giebeler wrote:
> C ist jetzt nicht so meine Domäne, aber:
> [...]
> bewirkt, dass das Endergebnis eins zu weit nach links geshiftet wird.
Stimmt. Müsste sich vermeiden lassen, indem man die beiden Zeilen 
vertauscht. Beim ersten mal ist es egal, dass einmal geschoben wird, 
steht eh ne Null drin...

> && ist doch nur für booleans oder? Wenn C eh implizite Typecasts zulässt
> sollte Folgendes gehen:
>
> [...]
>
> oder?
Nein, das geht nicht. value[i] ist kein Wahrheitswert. Genau deshalb 
muss ja erst mit irgendeiner logischen Verknüpfung einer draus gemacht 
werden. Und "&& 1" macht genau das. "|" ist hingegen wieder kein 
logischer, sondern ein bitweiser Operator. Das haut nicht hin.

Autor: Martin Kohler (mkohler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Interessanterweise hat noch keiner bemängelt, dass es "i--" anstelle 
"i++" heissen muss ;-)

Ich fasse dann mal zusammen:
uint8_t vector = 0;
for(int8_t i=7; i>=0; i--)
{
    vector <<= 1;
    vector |= value[i] ? 1 : 0;
}

Das Zielsystem ist übrigens ein Cypress Controller, mit KEIL 
programmiert.

Autor: Benedikt K. (benedikt) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oder ganz sicher und für jeden verständlich:
uint8_t vector;
for(uint8_t i=0; i<8; i++)
{
    vector >>= 1;
    if (value[i])
       vector |= 128;
}

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Martin Kohler wrote:
> Interessanterweise hat noch keiner bemängelt, dass es "i--" anstelle
> "i++" heissen muss ;-)
Schön, dass Du das selber rausgefunden hast. Wie sagte mein Mathe-Lehrer 
immer, wenn er was falsches an die Tafel geschrieben hatte und ein 
Schüler ihn drauf aufmerksam machte: "Wollte nur sehen, ob Sie auch 
aufpassen..."

Autor: Niels Hüsken (monarch35)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Martin Kohler wrote:
> Interessanterweise hat noch keiner bemängelt, dass es "i--" anstelle
> "i++" heissen muss ;-)

Nein, muss es nicht, aber da ist trozdem ein fehler. Intention war es 
wohl, i von 7 bis 0 zählen zu lassen. Da UINT8_T niemals <0 werden kann, 
haben wir eine endloschleife....

Insofern hast du schon recht....

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Niels Hüsken wrote:
> Das Logisch True "1" ergibt, ist Compiler/ Platform abhängig. Wenn der
> AVR-GCC das so macht, ist das OK, ist aber nicht standardisiert, soweit
> ich weiss.
Doch, ist es. Wäre sonst ein wenig chaotisch, wenn alles Mögliche 
rauskommen könnte.

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Benedikt K. wrote:
> Oder ganz sicher und für jeden verständlich:
>
>
> uint8_t vector;
> for(uint8_t i=0; i<8; i++)
> {
>     vector >>= 1;
>     if (value[i])
>        vector |= 128;
> }
> 

Ja, diese Version würde ich auch vorziehen. Obige ist zwar schön 
geschrieben, aber für Anfänger bspw. unverständlich, was da jetzt ein 
Logischer Operator soll. Der Code dürfte aber in beiden Fällen gleich 
sein.

Autor: Martin Kohler (mkohler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Uiuiui... gleich mehrere sich überschneidende Beiträge...!

Die Variante von Benedikt K. ist m.E. die einfachste und auch lesbarste 
--> wird so gewählt.

Danke für die Antworten!

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Niels Hüsken wrote:
> Nein, muss es nicht, aber da ist trozdem ein fehler. Intention war es
> wohl, i von 7 bis 0 zählen zu lassen. Da UINT8_T niemals <0 werden kann,
> haben wir eine endloschleife....
Doch, muss es. Genau deshalb steht da auch kein uint8_t, sondern ein 
int8_t, und der kann kleiner Null werden! War ein Tippfehler, weil ich 
das ganze andersrum angefangen habe (so, wie Benedikt es gemacht hat), 
und danach beim Ändern vergessen hab, aus dem "++" ein "--" zu machen...

Autor: Kai G. (runtimeterror)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>IMO wäre die x?1:0 Lösung vorzuziehen.
Ist auf jeden Fall die sauberste Lösung, wenn die casts nicht sauber 
definiert sind.

Unter folgendem Aspekt
>Wie codiere ich das am effizientesten in C?
muss der Autor zwischen Geschwindigkeit und Portabilität abwägen. Der 
ternäre Operator ist wahrscheinlich nicht so gut zu optimieren wie ein 
type cast.

Bin jetzt einfach mal von Effizienz = Geschwindigkeit ausgegangen...

>> && ist doch nur für booleans oder? Wenn C eh implizite Typecasts zulässt
>> sollte Folgendes gehen:
>>
>> [...]
>>
>> oder?
>Nein, das geht nicht. value[i] ist kein Wahrheitswert. Genau deshalb
>muss ja erst mit irgendeiner logischen Verknüpfung einer draus gemacht

Deshalb mache ich ja auch einen Integer-Vergleich um die Konversion 
vorzunehmen.

>werden. Und "&& 1" macht genau das. "|" ist hingegen wieder kein
>logischer, sondern ein bitweiser Operator. Das haut nicht hin.

Beim bitweisen Operator verlasse ich mich auf den impliziten Cast zum 
Integer (wie ihr oben auch mit dem Operator |= ). Sollte in meinen Augen 
also gut funktionieren.

Autor: Niels Hüsken (monarch35)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johannes M. wrote:
>> Das Logisch True "1" ergibt, ist Compiler/ Platform abhängig. Wenn der
>> AVR-GCC das so macht, ist das OK, ist aber nicht standardisiert, soweit
>> ich weiss.

> Doch, ist es. Wäre sonst ein wenig chaotisch, wenn alles Mögliche
> rauskommen könnte.

Nein, alles was nicht 0 ist, ist logisch "true". Und nein, es ist nicht 
Standardisiert. Auch da bin ich mir ziemlich sicher, weil ich das Thema 
schon öfter hatte.

Ich weiss z.B. das der Borland-C Compiler, mit dem ich mich beschäftigt 
habe, True immer als "-1" evaluiert hat....

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Kai:
> Deshalb mache ich ja auch einen Integer-Vergleich um die Konversion
> vorzunehmen.
Hast recht. Ist im Prinzip genau das, was ich geschrieben hatte, nur 
eben in einer Zeile. Kam mir nur zuerst ein bisschen komisch vor...

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Niels Hüsken wrote:
> Nein, alles was nicht 0 ist, ist logisch "true". Und nein, es ist nicht
> Standardisiert. Auch da bin ich mir ziemlich sicher, weil ich das Thema
> schon öfter hatte.
Dass alles, was nicht Null ist, true ist, ist mir klar, aber i.m.E. nur 
als Eingabewert. Dass das Ergebnis einer logischen Operation ebenfalls 
alles sein kann, wäre mir neu (und ich meine auch, mich erinnern zu 
können, dass wir das schon öfter hier hatten). Aber das dürfte sich 
überprüfen lassen.

Autor: Martin Kohler (mkohler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei diesem Code-Segment würde ich ja jetzt erwarten, dass am Schluss 
0x04 im Vektor steht:
  char value[8] = { 0, 0, 1, 0, 0, 0, 0, 0 };
  char vector = 0;
  count=0;

  for(i=0; i<8; i++)
  {
    vector >>= 1;
    if (value[i])
       vector |= 128;
  }

Aber was macht VisualStudio daraus? (jaaa, wer arbeitet schon damit... 
nur zu Testzwecken!)
Resultat: 0xFC  !!!!
Sobald eine 1 im MSB steht, werden nur noch 1 nachgeschoben, keine 0 
mehr?!?!

Ist das ein Bug oder ein Feature?

Autor: Kai G. (runtimeterror)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hehe ... die Schiebeoperation kopiert das oberste Bit. Einfach vector 
auf 16 bits Breite deklarieren, dann geht's.

Autor: Niels Hüsken (monarch35)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johannes M. wrote:
> Aber das dürfte sich überprüfen lassen.

Ja, das findest du irgendwo in den Dokumenten zum ISO/IEC 9899:1999 
Standard. Aber ich habs gerade mal überprüft. Der AVR-GCC evaluiert 
"True" auf jedenfall zu "1", also funktioniert value[x]&&1 auch 
richtig...

Autor: Martin Kohler (mkohler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kai Giebeler wrote:
> hehe ... die Schiebeoperation kopiert das oberste Bit.

Sicher?
  char value[8] = { 0, 0, 1, 0, 0, 0, 0, 0 };
  char vector = 0;
  count=0;

  for(i=8; i>0; i++)
  {
    vector <<= 1;
    if (value[i])
       vector |= 0x01;
  }

  count <<=1;
  count <<=1;

  count++;

  count <<=1;
  count <<=1;
Warum kommt dann hier vector=0xfe und count=0x04 raus??

Bei vector wird das unterste Bit kopiert (diesmal shift-right!), bei 
count jedoch nicht ???

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Martin:
Vorsicht! Keine Schiebeoperationen mit vorzeichenbehafteten Werten 
machen! Da kann nämlich tatsächlich alles Mögliche rauskommen. Ich hab 
schon mit Absicht einen uint8_t für vector genommen! Mach es wenn 
überhaupt dann mit einem unsigned char.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Martin Kohler wrote:
> Kai Giebeler wrote:
>> hehe ... die Schiebeoperation kopiert das oberste Bit.
>
> Sicher?

Nein.
Es hängt davon ab, ob für den Compiler ein plain vanilla 'char'
ein 'signed char' oder ein 'unsigned char' ist.

Du willst in diesem Fall auf jeden Fall, dass sich der
Compiler aus allem raushält und die Bits so nimmt wie
sie sind. Daher solltest du in diesem Fall explizit
sein und es nicht dem Compiler überlassen, was er nimmt.
Du willst unsigned char

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, ich hab grad mal im K&R (2. Auflage, ANSI C) nachgesehen und wurde 
zumindest von dieser Quelle bestätigt:

Zitat:
"By definition, the numeric value of a relational or logical expression 
is 1 if the relation is true, and 0 if the relation is false.
The unary negation operator ! converts a non-zero operand into 0, and a 
zero operand into 1."

Wenn der Borland-Compiler etwas anderes fabriziert, ist er entweder kein 
ANSI-C-Compiler oder der K&R lügt...

Autor: Martin Kohler (mkohler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kai Giebeler wrote:
> hehe ... die Schiebeoperation kopiert das oberste Bit. Einfach vector
> auf 16 bits Breite deklarieren, dann geht's.

Nachtrag: Die Schiebeoperation kopiert nur beim Datentyp "char" das 
oberste Bit, d.h. bei einer negativen Zahl werden 1 reingeschoben, bei 
einer positiven 0.

Bei unsigned char werden immer 0 reingeschoben.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Martin Kohler wrote:
> Nachtrag: Die Schiebeoperation kopiert nur beim Datentyp "char" das
> oberste Bit, d.h. bei einer negativen Zahl werden 1 reingeschoben, bei
> einer positiven 0.

Vorsicht mit dieser Aussage.
Ob char als 'signed char' oder als 'unsigned char' angesehen wird,
entscheidet der Compilerbauer. Der C-Standard lässt ihm diese
Freiheit.
Man kann also nicht generell sage, dass dieses Verhalten beim
Datentyp 'char' auftritt. Wenn der Compilerbauer eine 'char'
als 'unsigned char' aufgefasst hat, dann stimmt die Aussage
so nicht.

Viele Compiler haben auch Command Line switches mit der sich
die Vorgabe des Compilerbauers überschreiben lässt.

Autor: Martin Kohler (mkohler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger wrote:
> Vorsicht mit dieser Aussage.
> Ob char als 'signed char' oder als 'unsigned char' angesehen wird,
> entscheidet der Compilerbauer. Der C-Standard lässt ihm diese
> Freiheit.

Präzisierung:
hier kommt 0x10 raus:
  {
    unsigned char count = 0x80;
    count >>=1;
    count >>=1;
    count >>=1;
  }
und hier kommt 0xf0 raus:
  {
    signed char count = 0x80;
    count >>=1;
    count >>=1;
    count >>=1;
  }

Wo finde ich die Angabe des ANSI-Standards, dass bei signed char bei 
shift-right das MSB kopiert wird?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Martin Kohler wrote:
> Wo finde ich die Angabe des ANSI-Standards, dass bei signed char bei
> shift-right das MSB kopiert wird?

Im Grunde nirgends, das folgt aus der Verwendung des 2-er Komplements
für Arithmetik. Welches Verhalten >> und << bei signed Datentypen
haben ist meines Wissens so nicht eindeutig geregelt (genauso
wie beispielsweise das Overflow/Underflow Verhalten bei signed
Datentypen nicht geregelt ist). Da man aber Konsistenz haben will,
wird man das bei Verwendung von 2-er Komplement Arithmetik so machen,
damit der Zusammenhang zwischen Schiebeoperatio und Multiplikation
bzw. Division erhalten bleibt.

Aber auch hier Achtung: Im Grunde ist auch nirgends festgeschrieben,
dass 2-er Komplement verwendet werden muss. Kann mich aber nicht daran
erinnern je von einem Compiler gehört zu haben, der das nicht tut.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.