Forum: Mikrocontroller und Digitale Elektronik GCC Präprozessor soll Anzahl der Einsen in einem Byte ermitteln


von Phillip H. (philharmony)


Lesenswert?

Servus,
ich habe ein Byte zur Zuweisung von Funktionen das ich vorab im Code 
setzen/ändern möchte.
Im Programm soll eine Schleife so oft laufen, wie Einsen in dem Byte 
stehen.
Wie kann ich per Makro o.ä. die Anzahl der gesetzten Bits in einem Byte 
rausfinden?

von (prx) A. K. (prx)


Lesenswert?

(((b)&0x80)!=0) + (((b)&0x40)!=0) + ...

von STK500-Besitzer (Gast)


Lesenswert?

Wenn das nur zum Compilieren benutzt wird, kannst du lieber die Bits 
selber zählen. Das ist einfacher.

Wenn es im Programm auch variable eingesetzt werden soll, nimmst du eine 
Schleife von 1 bis 128 und multiplizierst den Schleifenwert immer mit 2.
Das ist dann eine Schleife, die 8 Mal durchlaufen wird.
In der Schleife vergleichst ("Logisches UND") du den Schleifenzähler mit 
deinem Byte und jedes Mal, wenn wenn der Vergleich positiv war, zählst 
du eine weitere Variable hoch.

von MaWin (Gast)


Lesenswert?

Macros mögen keine Rekursion, also lohnt der K&R BitCOunt nicht, man 
kann es auf die übersichtliche Art machen:

#define bits7(x) (x&0x80?1:0)
#define bits6(x) (x&0x40?1:0)+bits7(x)
#define bits5(x) (x&0x20?1:0)+bits6(x)
#define bits4(x) (x&0x11?1:0)+bits5(x)
#define bits3(x) (x&8?1:0)+bits4(x)
#define bits2(x) (x&4?1:0)+bits3(x)
#define bits1(x) (x&2?1:0)+bits2(x)
#define bits(x) ((x&1?1:0)+bits1(x))

Anwendung:

n = bits(0x22)

von Phillip H. (philharmony)


Lesenswert?

>Wenn das nur zum Compilieren benutzt wird, kannst du lieber die Bits
>selber zählen. Das ist einfacher.

Jo, das meine ich ja, und wie geht das?

von Uhu U. (uhu)


Lesenswert?

Nimm das, was A.K. vorgeschlagen hat.

von Phillip H. (philharmony)


Lesenswert?

Oh, den Beitrag hatte ich ganz übersehen.
Danke, werd ich mal so einbauen.
Grüße

von Sven P. (Gast)


Lesenswert?

MaWin schrieb:
> Macros mögen keine Rekursion, also lohnt der K&R BitCOunt nicht, man
> kann es auf die übersichtliche Art machen:
>
> #define bits7(x) (x&0x80?1:0)
> #define bits6(x) (x&0x40?1:0)+bits7(x)
> #define bits5(x) (x&0x20?1:0)+bits6(x)
> #define bits4(x) (x&0x11?1:0)+bits5(x)
> #define bits3(x) (x&8?1:0)+bits4(x)
> #define bits2(x) (x&4?1:0)+bits3(x)
> #define bits1(x) (x&2?1:0)+bits2(x)
> #define bits(x) ((x&1?1:0)+bits1(x))
>
> Anwendung:
>
> n = bits(0x22)

Über diese Brücke würde ich nicht unbedingt gehen.

von MaWin (Gast)


Lesenswert?

> Über diese Brücke würde ich nicht unbedingt gehen.

Mal abgesehen von 0x11,
Wir warten auf deinen besseren Vorschlag, aber da kommt sicher Nichts.
Den 4-zeiler hab ich wegen Unübersichtlichkeit absichtlich nicht 
gebracht.

von Phillip H. (philharmony)


Lesenswert?

A.K. Vorschlag funktioniert doch wunderbar, ist nachvollziehbar und 
einfach zu definieren und liefert wie gewünscht die Anzahl der Einsen in 
einem Byte zurück. Was mehr? Es geht nur um eine 
Präprozessor-Geschichte, da ist eventuelles Optimieren eh nicht so 
wichtig...

von Karl H. (kbuchegg)


Lesenswert?

Phillip Hommel schrieb:
> A.K. Vorschlag funktioniert doch wunderbar, ist nachvollziehbar und
> einfach zu definieren und liefert wie gewünscht die Anzahl der Einsen in
> einem Byte zurück. Was mehr? Es geht nur um eine
> Präprozessor-Geschichte, da ist eventuelles Optimieren eh nicht so
> wichtig...

Ich denke mit Optimieren hat das wenig zu tun.
Prärpozessor Makros sind generell gefährlich und man muss vorsichtig 
sein.

Wenn schon, würde ich noch eine inline Funktion drüberstülpen.
1
#define bits7(x) ( x&0x80?1:0 )
2
#define bits6(x) ( x&0x40?1:0 ) + bits7(x)
3
#define bits5(x) ( x&0x20?1:0 ) + bits6(x)
4
#define bits4(x) ( x&0x10?1:0 ) + bits5(x)
5
#define bits3(x) ( x&0x08?1:0 ) + bits4(x)
6
#define bits2(x) ( x&0x04?1:0 ) + bits3(x)
7
#define bits1(x) ( x&0x02?1:0 ) + bits2(x)
8
#define bits0(x) ( x&0x01?1:0 ) + bits1(x)
9
10
uint8_t bits( uint8_t arg )
11
{
12
  return bits0( arg );
13
}

damit mich Fälle wie
1
   i = bits( j++ );
2
   i = bits( 5 + 8 );
nicht in den Wahnsinn treiben.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Phillip Hommel schrieb:
> Servus,
> ich habe ein Byte zur Zuweisung von Funktionen das ich vorab im Code
> setzen/ändern möchte.
> Im Programm soll eine Schleife so oft laufen, wie Einsen in dem Byte
> stehen.
> Wie kann ich per Makro o.ä. die Anzahl der gesetzten Bits in einem Byte
> rausfinden?

Bits zählt man am einfachsten so:
1
#include <stdint.h>
2
3
uint8_t bitcount (uint8_t x)
4
{
5
    uint8_t count = 0;
6
7
    while (x != 0)
8
    {
9
        count++;
10
        x &= x-1;
11
    }
12
13
    return count;
14
}

Analog wenn das in einer Schleife sein soll:
1
uint8_t bits;
2
uint8_t wert = ...;
3
4
for (bits = wert; bits; bits &= bits-1)
5
{
6
    // mach was 
7
}

Johann

von Phillip H. (philharmony)


Lesenswert?

@ Johann,
ich möchte aber nicht zur Laufzeit sondern vorab die Bitzahl wissen da 
diese zur Laufzeit fix ist.
Spezialfälle kommen bei mir nicht vor da ich das ganze nur an drei oder 
vier stellen benutze und ich da nur ein fertiges Byte zw 0x00 und 0xff 
übergebe.
Da funktioniert das simple Makro doch hervorragend.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Weitere Möglichkeutist bei Verwendung von gcc die Magie von 
__builtin_popcount (oder __builtin_popcount32?), für 32-Bit Variablen.

Oder weiterlesen in

http://gurmeetsingh.wordpress.com/2008/08/05/fast-bit-counting-routines/

Johann

von Karl H. (kbuchegg)


Lesenswert?

Es gäbe dann noch die Variante: Time For Space

Das Byte in 2 Nibbel zerlegen und damit in einer Tabelle die Anzahl der 
gesetzten Bits ablesen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Phillip Hommel schrieb:
> @ Johann,
> ich möchte aber nicht zur Laufzeit sondern vorab die Bitzahl wissen da
> diese zur Laufzeit fix ist.

Dann verwende __builtin_popcount. Wenn der Wert zur Compilezeit bekannt 
ist, wertet GCC das aus und ersetzt es durch die entsprechende 
Konstante.

Da Makro oben von A.K. müsste auch gehen; gcc sollte den entstehenden 
recht komplexen Ausdruck zu ner Konstanten falten (falls ihm nicht 
irgendwelche "Optimierungs-Kapriolen" zu Kopfe steigen).

Johann

von Sven P. (Gast)


Lesenswert?

MaWin schrieb:
>> Über diese Brücke würde ich nicht unbedingt gehen.
>
> Mal abgesehen von 0x11,
> Wir warten auf deinen besseren Vorschlag, aber da kommt sicher Nichts.
> Den 4-zeiler hab ich wegen Unübersichtlichkeit absichtlich nicht
> gebracht.

Spar dir solches Gesülze und probier mal folgendes mit deiner Variante:
1
#define bits7(x) (x&0x80?1:0)
2
#define bits6(x) (x&0x40?1:0)+bits7(x)
3
#define bits5(x) (x&0x20?1:0)+bits6(x)
4
#define bits4(x) (x&0x11?1:0)+bits5(x)
5
#define bits3(x) (x&8?1:0)+bits4(x)
6
#define bits2(x) (x&4?1:0)+bits3(x)
7
#define bits1(x) (x&2?1:0)+bits2(x)
8
#define bits(x) ((x&1?1:0)+bits1(x))
9
10
11
int n = bits(1 + 0);

(Ja, da fehlen Klammern)

von MaWin (Gast)


Lesenswert?

> probier mal folgendes mit deiner Variante

Brauch ich nicht, braucht Philipp nicht,
aber du kannst gerne Klammern spendieren.

Dein Beitrag war für'n Arsch.

von Sven P. (Gast)


Lesenswert?

Dein Quelltext war nicht ausreichend getestet. Toll, ne?

Mir reichts, ist mir zu blöde.

von Vlad T. (vlad_tepesch)


Lesenswert?

hört auf euch zu anzuflamen und bleibt sachlich


um das argument gehören immer klammern, ich würd also noch mehr setzen.
Selbst wenn es zum derzeitigen Zeitpunkt wirklich nur für einfache 
Konstanten genutzt wird.
Beim nächstem mal steckt man vielleicht was anderes rein und hat die 
Randbbedingungen schon wieder vergessen
1
#define bits7(x) ((x)&0x80?1:0)
2
#define bits6(x) ((x)&0x40?1:0)+bits7(x)
3
#define bits5(x) ((x)&0x20?1:0)+bits6(x)
4
#define bits4(x) ((x)&0x11?1:0)+bits5(x)
5
#define bits3(x) ((x)&8?1:0)+bits4(x)
6
#define bits2(x) ((x)&4?1:0)+bits3(x)
7
#define bits1(x) ((x)&2?1:0)+bits2(x)
8
#define bits(x) (((x)&1?1:0)+bits1(x))

obwohl ich das ganze in ein define packen würde, um den namespace nicht 
so vollzumüllen


Edit:
bits ist vielleicht auch nicht der geeigneteste Name dafür.

von Axel H. (axelh)


Lesenswert?

Hallo Karl heinz,

> Wenn schon, würde ich noch eine inline Funktion drüberstülpen.

Den Tip werde ich mir mal merken. Das ist eigentlich eine recht elegante 
Lösung für gefährliche Macros, die ich bisher nicht kannte. Und eine 
gewisse Typensicherheit bekommt das ganze auch noch. DANKE!

Axel

von (prx) A. K. (prx)


Lesenswert?

Wobei man das dann auch nicht drüberstülpen muss, sondern gleich so ohne 
Verwendung eines Makros realisieren kann. Das hat neben einigen 
Vorteilen aber auch Nachteile.

Eine reine Konstantenrechnung im Makro wird immer vom Compiler fertig 
ausgewertet, eine Inline-Funktion abhängig von Optimierungsgrad, 
Compilerversion und Wasserstand. Und das Ergebnis einer 
Konstantenrechnung kann man in einem #if abfragen.

von Axel H. (axelh)


Lesenswert?

Hallo A. K.,

das mir der Auswertung von Inline-Funktion durch den Compiler ist so 
eine Sache. Eigentlich sollte er das machen und eigentlich sollte der 
Optimierer das erkennen. Aber ich habe schon zu oft gesehen, dass 
Compiler das nicht machen bzw. schnell bei Verschachtelungen aufgeben. 
Und da hilft es dann auch nicht, dem Compiler dazu zu zwingen mit 
irgendwelchen Aufruf-Parametern oder Funktions-Attributen.
Ausserdem kommt auch noch hinzu, dass bei einem Debug-Build 
normalerweise nicht Optimiert wird, damit ich Dinge nachvollziehbar 
bleiben. Trotzdem sollten aber so "einfache" Sachen wie das Zählen von 
Bits oder das berechnen von Offsets vom Compiler erledigt werden - sonst 
passt der Code einfach nicht in den Chip. Dann sind Macro die bessere 
Wahl und ein inline-Wrapper macht das ganze noch etwas sicherer.

Aber über sowas kann man sich sowieso vortrefflich streiten. Und 
vielleicht wird das mit LLVM Compilern irgendwann mal besser .... ;)

Axel

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.