Forum: Projekte & Code print binary


von Apollo M. (Firma: @home) (majortom)


Lesenswert?

... aus meiner (arduino, uC) Giftküche, type val independent
1
char rxBuf[42];
2
//*****************************************************************
3
void printBin(uint32_t val, const bool d) { //d: 0/1 forward/backward
4
//***************************************************************** 
5
  char *pbuf = rxBuf;
6
  for (uint8_t i=0; i!=sizeof(val)*8; d? val>>=1:val<<=1, i++) {
7
    if (i && !(i%4)) *pbuf++ = '.';
8
    *pbuf++ = (val & (d? 1:((typeof(val))1<<(sizeof(val)*8-1))))? '1':'0';
9
  }
10
  *pbuf++ = '\n'; *pbuf = '\0';
11
  Serial.print(rxBuf);
12
}

: Verschoben durch Admin
von Walter T. (nicolas)


Lesenswert?

Warum?

von Thilo L. (bc107)


Lesenswert?

Ich bezweifle nicht, dass dieser Code das genialste Stückchen Software 
auf Erden ist, den schnellsten und kürzesten Code, um das gegebene 
Problem zu lösen, erzeugt, und auch sonst das Leben ein Stück 
lebenswerter macht.

Der gezeigte Code macht auch deutlich, dass die bei manchen 
Programmierern teilweise vorherrschende Meinung, Kommentare 
erleichterten das Verständnis oder auch nur die Verwendung in eigenen 
Programmen, hoffnungslos überbewertet ist.

Ich nehme mal an, dass dieser Code eine 32bit-Zahl in Binärschreibweise 
darstellt. Und ich nehme mal an, dass der Parameter d die Position des 
LSBit (entweder links oder rechts) angibt. Und ich nehme mal an, dass es 
sonst keinerlei Nebenwirkungen gibt.

Und natürlich hagelt es jetzt schnippische Antworten wie etwa "steht 
doch da: "//d: 0/1 forward/backward". Das ist für mich aber kein 
verwertbarer Kommentar, das könnte genausogut eine dieser kryptischen 
Codierungen für irgendwelche Linux-Tools zur automatischen 
Kommentargenerierung sein, aber kein wirklich menschenverständlicher 
Hilfetext. Und wenn ich den Code erst durcharbeiten muss, um die 
Kommentare zu verstehen, dann, ja dann haben die Kommentare wirklich 
ihren Zweck vollumfänglich erfüllt.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Arduino ist doch C++. Da geht es wirklich Typ-Unabhängig. Ständig "d" 
abzufragen ist ziemlich ineffizient, besser ist es zwei Schleifen mit 
äußerer Unterscheidung zu verwenden:
1
char rxBuf[42];
2
3
template <typename T>
4
void printBin (T val, const bool d) { //d: 0/1 forward/backward
5
  static_assert (std::is_unsigned<T>::value, "Can only print unsigned types");
6
  char* pbuf = rxBuf;
7
  const std::size_t maxBuf = sizeof (rxBuf);
8
  // Maximale Anzahl ausgebbarer Bits (lasse 2 Bytes frei für Zeilenumbruch & 0-Byte)
9
  const std::size_t maxBits = std::min<std::size_t> (maxBuf - 2, sizeof(val)*CHAR_BIT);
10
  if (d) {
11
    // Niederwertigstes Bit zuerst
12
    for (std::uint8_t i = 0; i < maxBits; ++i) {
13
      // 4er-Trennzeichen
14
      if (i && !(i%4)) *pbuf++ = '.';
15
      // Prüfe unterstes Bit
16
      *pbuf++ = (val & 1) ? '1' : '0';
17
      val >>= 1;
18
    }
19
  } else {
20
    // Höchstwertigstes Bit zuerst
21
    for (std::uint8_t i = 0; i < maxBits; ++i) {
22
      // 4er-Trennzeichen
23
      if (i && !(i%4)) *pbuf++ = '.';
24
      // Prüfe höchstes Bit
25
      *pbuf++ = (val & (T { 1 } << (std::numeric_limits<T>::digits-1))) ? '1':'0';
26
      val <<= 1;
27
    }
28
  }
29
  *pbuf++ = '\n'; *pbuf = '\0';
30
  Serial.print(rxBuf);
31
}

Wobei man den Puffer eventuell besser als Zeiger übergeben sollte, je 
nachdem was der Gedanke dabei ist...

von DerEinzigeBernd (Gast)


Lesenswert?

Worüber der eine oder andere Compiler stolpern dürfte, ist das hier 
verwendete typeof, das ist bislang kein Bestandteil des 
C-Sprachstandards, sondern nur eine nichtportable Erweiterung mancher 
Compiler.

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Niklas G. schrieb:
> Arduino ist doch C++. Da geht es wirklich Typ-Unabhängig. Ständig "d"
> abzufragen ist ziemlich ineffizient, besser ist es zwei Schleifen mit
> äußerer Unterscheidung zu verwenden:

Das sind Kommentare wie ich sie mag ... zum nachdenken/lernen.

Thilo L. schrieb:
> Ich bezweifle nicht, dass dieser Code das genialste Stückchen Software
> auf Erden ist,

... das Gegenteil - rumgesülze!

von Klaus W. (mfgkw)


Lesenswert?

Wenn man gcc hat, kann man auch gleich eine Formatierung für Binärzahlen 
in printf einbauen und z.B. mit %b ausgeben.

Bspw. 
https://codereview.stackexchange.com/questions/219994/register-b-conversion-specifier

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Apollo M. schrieb:
> ... aus meiner (arduino, uC) Giftküche,

"Giftküche", offensichtlich gut gewählt, da einige Hirne gleich unter 
Drogen zu stehen scheinen.

Coding ist Art und darüber lässt sich bekanntlich lange diskutieren ...


Es wäre auch interessant, wenn regelmäßig Code Snippets zur Diskursion 
gestellt werden. Dann gibt es vielleicht hier mal zur Abwechselung 
wieder mehr Inhalt!!!

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Klaus W. schrieb:
> Wenn man gcc hat, kann man auch gleich eine Formatierung für Binärzahlen
> in printf einbauen und z.B. mit %b ausgeben.

printf scheidete vom memory footprint aus.

Niklas G. schrieb:
> Arduino ist doch C++.

Von C++ habe ich zu wenig Ahnung ..., aber vielleicht wird das mal 
irgendwann besser.

Niklas G. schrieb:
> Ständig "d"
> abzufragen ist ziemlich ineffizient,

Inefficient? bzgl. memory size oder run time oder beides?
Wie immer kommt drauf an ...

: Bearbeitet durch User
von Apollo M. (Firma: @home) (majortom)


Lesenswert?

DerEinzigeBernd schrieb:
> Worüber der eine oder andere Compiler stolpern dürfte, ist das hier
> verwendete typeof, das ist bislang kein Bestandteil des
> C-Sprachstandards,

Stimmt leider, ausprobiert mit xc8 ...

: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Apollo M. schrieb:
> Inefficient? bzgl. memory size oder run time oder beides?
> Wie immer kommt drauf an ...

Runtime. In jedem Schleifendurchlauf sind gleich 2 Fallunterscheidungen, 
die dann z.B. 32x gemacht werden müssen. Hat man wie bei mir nur eine 
Abfrage, kommt die Unterscheidung nur 1x. Fallunterscheidungen sind 
allgemein langsam, insbesondere Prozessoren mit (längerer) Pipeline 
(z.B. ARM, gibts ja auch bei Arduino), daher sollte man davon möglichst 
wenige in inneren Schleifen haben.

Bei Prozessoren mit Branch-Prediction ist es nicht so schlimm weil sich 
d nicht ändert, aber das haben nicht viele Mikrocontroller (Cortex-M7 
z.B. hat es).

: Bearbeitet durch User
von DerEgon (Gast)


Lesenswert?

Apollo M. schrieb:
> zur Diskursion

Damit wir dann Rezessionen davon verfassen? Ist das Deine Intension?

von Gerhard (Gast)


Lesenswert?

Apollo M. (Firma: @home) (majortom)
17.06.2022 08:36
>... aus meiner (arduino, uC) Giftküche, type val independent

Einerseits finde ich es gut, wenn jemand Code posted, damit die anderen 
etwas lernen können.

Andererseits würde ich dir dringend empfehlen, anderseits würde ich dir 
dringend das Buch "weniger schlecht programmieren"

https://oreilly.de/produkt/weniger-schlecht-programmieren/

oder "Clean Code" ans Herz legen falls du mal vor hast, leserlichen Code 
zu schreiben.

von Klaus W. (mfgkw)


Lesenswert?

Niklas G. schrieb:
> Fallunterscheidungen sind
> allgemein langsam

Das könnte man auf die Spitze treiben und gleich ganz drauf verzichten 
(erstmal). Nur wenn man es wirklich braucht, lässt sich der String im 
Nachhinein drehen.
Dann kommt das Konvertieren bis dahin komplett ohne Fallunterscheidung 
aus.

Da es ja auch nur 16 Möglichkeiten für die Teilstrings zwischen den 
Punkten gibt, könnte eine Tabelle dafür effizienter sein, mit jeweils 
einem Nibble als Index.
Zumindest würde ich das mal auf dem jeweiligen System als eine 
Möglichkeit testen.

Das würde dann etwa so aussehen:
1
char rxBuf[42];
2
3
void printBin( uint32_t value, const bool backward )
4
{
5
  const size_t destLenNibble = 5; // 4 binary digits + '.'
6
  static const char *nibbleStringTable[] =
7
    {
8
     "0000.", "0001.", "0010.", "0011.", "0100.", "0101.", "0110.", "0111.",
9
     "1000.", "1001.", "1010.", "1011.", "1100.", "1101.", "1110.", "1111.",
10
    };
11
  const int   nNibbles     = sizeof(value)*2;
12
  char       *destination  = rxBuf+(nNibbles-1)*destLenNibble;
13
14
  for( int iNibble=0; iNibble<nNibbles; ++iNibble )
15
  {
16
    memcpy( destination, nibbleStringTable[value&0x0F], destLenNibble );
17
    destination -= destLenNibble;
18
    value >>= 4;
19
  }
20
21
  // terminate string
22
  rxBuf[nNibbles*destLenNibble-1] = '\0';
23
24
  // reverse string if required:
25
  if( backward )
26
  {
27
    destination = rxBuf;
28
    char *end = rxBuf + nNibbles*destLenNibble - 2;
29
    while( destination < end )
30
    {
31
      char   tmp = *destination;
32
      *destination++ = *end;
33
      *end-- = tmp;
34
    }
35
  }
36
}

So habe ich acht Schleifendurchläufe mit je:
- Berechnung Tabellenzugriff mit einem &
- memcpy für je 5 Byte
- Zeigerkorrektur mit -=
- 32 Bit um 4 nach rechts schieben

Danach noch den String terminieren, und evtl. den String drehen 
(Schleife mit halber Stringlänge)

(Die abschließende 0 überschreibt einen vorher versehentlich 
geschriebenen Punkt. Das nehme ich in Kauf, weil es umständliche 
Fallunterscheidungen eliminiert.)

Wen man sehr mit Speicher geizt, tut vielleicht die Tabelle weh. Aber 
umständlicher Code kostet ja auch...

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Gerhard schrieb:
> leserlichen Code
> zu schreiben.

Für wenn? - Analphabeten, sind nicht meine Zielgruppe!
Ich mag den Code kompakt, das sinnlose Klammern von einzeiligen if/else 
.. Anweisungen kann ich nicht ausstehen, genauso wenig die oft nur 
sinnleeren Komentare.

Gerhard schrieb:
> oder "Clean Code" ans Herz

Kenn ich und überzeugt mich nicht, genau so wenig wie MiSRA ...
und Empfehlungen von selbsternannten Experten sind mir besondern 
unerwünscht!

von Klaus W. (mfgkw)


Lesenswert?

Apollo M. schrieb:
> Für wenn? - Analphabeten,

ah.... :-)

von Klaus W. (mfgkw)


Lesenswert?

Apollo M. schrieb:
> char rxBuf[42];

Wieso eigentlich 42?
Wenn ich mich nicht verzähle reichen 40.
32 mal '0' oder '1', 7 mal '.' zum Trennen und eine abschließende \0.

: Bearbeitet durch User
von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Klaus W. schrieb:
> static const char *nibbleStringTable[] =
>     {
>      "0000.", "0001.", "0010.", "0011.", "0100.", "0101.", "0110.",
> "0111.",
>      "1000.", "1001.", "1010.", "1011.", "1100.", "1101.", "1110.",
> "1111.",
>     };

Auch interessant - mal schauen, was das hins. code size bedeutete.

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Klaus W. schrieb:
> Wieso eigentlich 42?

Der Buffer ist für alle Ausgaben und nicht nur für printBin. Also nimm 
was du willst ...

von Walter T. (nicolas)


Lesenswert?

An dieser Stelle sei noch einmal auf meine obige Frage verwiesen.

Was willst Du erreichen - mit dem Thread und mit der Funktion?

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Apollo M. schrieb:
> Stimmt leider, ausprobiert mit xc8 ...

xc8 kennt anstatt _typeof_ !

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Apollo M. schrieb:
> ... aus meiner (arduino, uC) Giftküche, type val independent
>
>
1
> char rxBuf[42];
2
> //*****************************************************************
3
> void printBin(uint32_t val, const bool d) { //d: 0/1 forward/backward
4
> //*****************************************************************
5
>   char *pbuf = rxBuf;
6
>   for (uint8_t i=0; i!=sizeof(val)*8; d? val>>=1:val<<=1, i++) {
7
>     if (i && !(i%4)) *pbuf++ = '.';
8
>     *pbuf++ = (val & (d? 1:((typeof(val))1<<(sizeof(val)*8-1))))? 
9
> '1':'0';
10
>   }
11
>   *pbuf++ = '\n'; *pbuf = '\0';
12
>   Serial.print(rxBuf);
13
> }
14
> 
15
>

Schönes Beispiel dafür, wie man C als "Klartextverschlüsselung" 
missbrauchen kann. Völlig kontraproduktiv. Wenn ich eine "Hochsprache" 
einsetze, ist das Ziel, die Sache leichter les- und wartbar zu machen.

Mein Gott, selbst die Asm-Umsetzung dieses Bullshits ist zwar nicht 
nennenswert schneller, aber sehr viel besser lesbar...

von c-hater (Gast)


Lesenswert?

c-hater schrieb:

> Mein Gott, selbst die Asm-Umsetzung dieses Bullshits ist zwar nicht
> nennenswert schneller, aber sehr viel besser lesbar...

Ich muss mich hier nochmal korrigieren. Die wirklich durchdachte 
Asm-Umsetzung ist deutlich schneller, deutlich kleiner und immer noch 
deutlich besser lesbar...

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

c-hater schrieb:
> Mein Gott, selbst die Asm-Umsetzung dieses Bullshits ist zwar nicht
> nennenswert schneller, aber sehr viel besser lesbar...

Was geht mich fremdes Elend an, ich kann es sehr gut lesen und mehr 
interessiert nicht!
Asm-Affe, nimm besser zwei Bananen und entspann in deiner 
closed-asm-box!

Beitrag #7100533 wurde von einem Moderator gelöscht.
von Stefan S. (chiefeinherjar)


Lesenswert?

Apollo M. schrieb:
> c-hater schrieb:
>> Mein Gott, selbst die Asm-Umsetzung dieses Bullshits ist zwar nicht
>> nennenswert schneller, aber sehr viel besser lesbar...
>
> Was geht mich fremdes Elend an, ich kann es sehr gut lesen und mehr
> interessiert nicht!
> Asm-Affe, nimm besser zwei Bananen und entspann in deiner
> closed-asm-box!

Walter T. schrieb:
> Was willst Du erreichen - mit dem Thread und mit der Funktion?

Einfach mal provozieren und anschließend rumpöbeln. Etwas anderes ist 
offenbar nicht der Sinn - denn darum, jemandem zu helfen, der das 
gleiche Problem haben könnte, geht's ganz offensichtlich nicht.

von Gerhard (Gast)


Lesenswert?

>c-hater schrieb:

>> Mein Gott, selbst die Asm-Umsetzung dieses Bullshits ist zwar nicht
>> nennenswert schneller, aber sehr viel besser lesbar...

Die Formulierung "Bullshit" mag ich nicht, aber in einem Punkt muss ich 
dir Recht geben: Dieser Banalalgortihmus formuliert jemand der mit C 
umgehen kann deutlich besser. Es gibt keinerlei Grund, diesen 
Algorithmus nicht klar und deutlich hinzuschreiben außer vielleicht die 
Begründung "ich machs halt so und wenn ihr zu blöd seit, es zu lesen, 
ist es eure Schuld". In einer Firma mit großen Softwareteams müsste man 
sich bald einen anderen Job suchen.

von Horst G. (horst_g532)


Lesenswert?

Gerhard schrieb:
> Dieser Banalalgortihmus formuliert jemand der mit C umgehen kann
> deutlich besser. Es gibt keinerlei Grund, diesen Algorithmus nicht klar
> und deutlich hinzuschreiben außer vielleicht die Begründung "ich machs
> halt so und wenn ihr zu blöd seit, es zu lesen, ist es eure Schuld". In
> einer Firma mit großen Softwareteams müsste man sich bald einen anderen
> Job suchen.

So sieht's aus.
Selbsternannte Experten wie der TO ("MISRA und Coding Guidelines kenne 
ich zwar, interessiert mich aber nicht"), die glauben, die Genialität 
eines Quellcodes hängt ausschließlich reziprok von der Anzahl der 
Tastaturanschläge ab, halten es üblicherweise in meinen Teams auch nicht 
lange aus. Dazu muss nicht einmal ich die Keule "Entlassungsgrund: 
Arbeitsverweigerung durch vorsätzliche Nichteinhaltung einschlägiger 
Arbeitsvorschriften" schwingen; üblicherweise reicht schon der Druck der 
anderen Teammitglieder, die die Ergüsse des fraglichen Mitarbeiters 
verwerten müssen, aus.

Als Hobbyist sage ich auch: Code ist unklar beschrieben und 
strukturiert; bevor ich mich hier reindenke, schreibe es lieber selbst 
oder nehme eine andere, gut dokumentierte und getestete Funktion (denn 
auch das scheint der Autor in seiner Genialität ja nicht zu benötigen).

von MaWin (Gast)


Lesenswert?

c-hater schrieb:
> Ich muss mich hier nochmal korrigieren. Die wirklich durchdachte
> Asm-Umsetzung ist deutlich schneller, deutlich kleiner und immer noch
> deutlich besser lesbar...

Apollo liefert zumindest irgendwas, du lieferst nichts, nur Erbrochenes.

von W.S. (Gast)


Lesenswert?

MaWin schrieb:
> Apollo liefert zumindest irgendwas, du lieferst nichts, nur Erbrochenes.

Die Projekte hier sollen eigentlich den Lesern ein möglichst gutes 
Beispiel liefern. Da wäre garkein Beispiel durchaus besser als ein 
grottenschlechtes Beispiel.

Mal davon abgesehen frage ich mich, warum dem TO nicht selber folgendes 
aufgefallen ist:
Apollo M. schrieb:
> *pbuf++ = (val & (d? 1:((typeof(val))1<<(sizeof(val)*8-1))))? '1':'0';

wo er doch zuvor folgendes geschrieben hat:
Apollo M. schrieb:
> uint32_t val

Ist das der Hang zur Obfuskation?

W.S.

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.