Hallo,
ich habe leider nichts vernünftiges im Forum oder Google gefunden...
Daher die Frage:
kann ich über die Funktion utoa auch strings mit Anführungsnullen
erzeugen?
Ich möchte Werte binär ausgeben, leider schneidet utoa immer die Nullen
am Anfang ab, so dass statt 00010110 nur 10110 ausgegeben wird...
gibts da irgend eine Möglichkeit?
Ansonsten müsste ich mir ne eigene Funktion schreiben...
Erik Her schrieb:> buffer[i] = 49; //wenn <> 0, dann char = 49 = '1'
Warum weist du 49 zu und erklärst dann in einem Kommentar, daß damit '1'
gemeint ist, statt einfach gleich '1' zuzuweisen?
> ist wohl nicht sonderlich effizient, aber funktioniert.
Ich sehe jetzt nichts ineffizientes daran.
braucht unnötig viele Taktzyklen...
(bin mir nicht sicher, in wie viele Schritte die Division kompiliert
wird)
Außerdem hatte ich gehofft das ganze ohne if-Abfrage zu gestalten:
nach dem Bit-Vergleich eine 1 oder 0 zu erhalten und dann 48 dazu
addieren. Das ergibt dann eine '1' oder '0'
__________________________________
1
byte<<=1;//nächstes Bit vergleichen
diesen "<<=" Operator habe ich noch nie gesehen und google findet ihn
auch nicht... Was macht der?
Läuft auch damit!
Die Änderung spart am Ende 6 Byte Programmspeicher... (zuzüglich 1 Byte
SRAM)
Erik Her schrieb:> diesen "<<=" Operator habe ich noch nie gesehen und google findet ihn> auch nicht... Was macht der?
Das ist ein Bitshift-Operator.
z << a verschiebt um a Stellen nach links, >> dementsprechend nach
rechts.
> braucht unnötig viele Taktzyklen...> (bin mir nicht sicher, in wie viele Schritte die Division kompiliert> wird)
Da j ein uint8_t ist, wird das in genau einen Schiebebefehl übersetzt.
Hört endlich auf mit diesem Unsinn, Multiplikationen und Divisionen mit
2-er Potenzen selbst dursch Shift zu ersetzten! Compiler machen diese
Ersetzung seit mehr als 40 Jahren völlig autonom! Compilerbauer sind
doch keine Trottel.
> Außerdem hatte ich gehofft das ganze ohne if-Abfrage zu gestalten:> nach dem Bit-Vergleich eine 1 oder 0 zu erhalten und dann 48 dazu> addieren. Das ergibt dann eine '1' oder '0'
Das kannst du im Prinzip machen, aber effizienter wird es dadurch
wahrscheinlich auch nicht. Denn zunächst muss ja das Ergebnis des
Vergleichs von 0/nicht_0 auf 0/1 normiert werden. Daher gewinnst du
nichts. Die C Schreibweise ist ein wenig kürzer, aber das bedeutet nicht
viel.
@ Karl heinz Buchegger (kbuchegg) (Moderator)
>Da j ein uint8_t ist, wird das in genau einen Schiebebefehl übersetzt.
Kann sein, muss nicht.
>Hört endlich auf mit diesem Unsinn, Multiplikationen und Divisionen mit>2-er Potenzen selbst dursch Shift zu ersetzten!
Erstens ist die Schiebeoperation hier DEUTLICH logischer, man versteht
worum es geht.
> Compiler machen diese>Ersetzung seit mehr als 40 Jahren völlig autonom! Compilerbauer sind>doch keine Trottel.
Zweitens ist das schlicht so allgemein nicht wahr. Hab ich letztens auf
dem MPLAB C-Compiler von Microchip gesehen, eine Schiebeoperation war
deutlich schneller als eine Divison mit der entsprechenden Zahl. Und es
waren KONSTANTEN!!
@ Erik Her (agutanus)
>Außerdem hatte ich gehofft das ganze ohne if-Abfrage zu gestalten:>nach dem Bit-Vergleich eine 1 oder 0 zu erhalten und dann 48 dazu>addieren. Das ergibt dann eine '1' oder '0'
Das geht nur wenn du beim LSB anfängst.
1
buffer[i]=(byte&0x01)+'0';
So funktioniert das normale itoa. Siehe Festkommaarithmetik.
Ist aber zumindest auf dem AVR nicht schneller, der kann einzelne Bits
testen und verzweigen.
>diesen "<<=" Operator habe ich noch nie gesehen und google findet ihn>auch nicht... Was macht der?
Schieben und zuweisen
1
a<<=1;// kurz
2
a=a<<1;// lang, identisch
>Die Änderung spart am Ende 6 Byte Programmspeicher... (zuzüglich 1 Byte>SRAM)
Die können manchmal entscheidend sein. In einem Hobbyprojekt hab ich mal
einen ATmega8515 bis auf 4 (VIER) Bytes Flash voll ausgereizt. Das ging
aber erst nach Optimierung und Mikrooptimierung des Codes.
MfG
Falk
Karl heinz Buchegger schrieb:> Da j ein uint8_t ist, wird das in genau einen Schiebebefehl übersetzt.>> Hört endlich auf mit diesem Unsinn, Multiplikationen und Divisionen mit> 2-er Potenzen selbst dursch Shift zu ersetzten!
Ich weiß, daß da ein gewisser Reflex einsetzt, wenn jemand eine Division
durch einen Shift ersetzt, aber manchmal paßt der Shift tatsächlich
besser. Immerhin geht es in dem Code darum, schrittweise durch alle Bits
eines Bytes zu gehen und jeweils zu schauen, ob es gesetzt ist, und
dafür wird ein gesetztes Bit durch eine Variable geschoben. Da stellt
sich dann die Frage, ob es sinnvoll ist, den Shift durch eine Division
zu ersetzen, nur weil der Compiler dann eh wieder einen Shift daraus
macht ;-)
Allerdings scheint der Compiler damit Probleme zu haben...
Das Programm ist nun um 130 (!!!) Bytes kleiner, aber nicht mehr
lauffähig.
anscheinend hängt es sich in der Funktion auf.
Erik Her schrieb:> Habe die Funktion erneut umgeschrieben:> void my_btoa(uint8_t byte, char* buffer)> {> uint8_t i; //Zähler (Schleife)> for(i=7; i>=0; i--)
Da i ein uint8_t ist, kann i per Definition immer nur >= 0 sein. Es ist
schlicht und ergreifend nicht möglich, dass i>=0 jemals falsch wird.
Falk Brunner schrieb:>> Zweitens ist das schlicht so allgemein nicht wahr. Hab ich letztens auf> dem MPLAB C-Compiler von Microchip gesehen, eine Schiebeoperation war> deutlich schneller als eine Divison mit der entsprechenden Zahl. Und es> waren KONSTANTEN!!
Dann nimm einen vernünftigen Compiler.
Das ist doch lächerlich, dass wir alle paar Wochen wieder dieselbe
Diskussion haben. Wenn der Micochip Compiler das nicht hinkriegt, dann
hast du entweder signed statt unsigned Variablen oder der Compiler ist
einfach nur schwach. Diese Optimierung ist von der allereinfachsten
Sorte und es gibt keinen Grund warum ein Compiler das nicht können
sollte (es sei denn die Compilerbauer sind komplett zugekifft).
Ein Anfänger soll sich in erster Linie auf sein Problem konzentrieren
und nicht auf diese vermeintlich "cleveren" Optimierungen, die sich
regelmässig als Zeitbomben entpuppen.
Rolf Magnus schrieb:> Karl heinz Buchegger schrieb:>> Da j ein uint8_t ist, wird das in genau einen Schiebebefehl übersetzt.>>>> Hört endlich auf mit diesem Unsinn, Multiplikationen und Divisionen mit>> 2-er Potenzen selbst dursch Shift zu ersetzten!>> Ich weiß, daß da ein gewisser Reflex einsetzt, wenn jemand eine Division> durch einen Shift ersetzt, aber manchmal paßt der Shift tatsächlich> besser.
Richtig.
Allerdings war es hier die Sorge des TO, dass eine Division zu langsam
wäre.
> sich dann die Frage, ob es sinnvoll ist, den Shift durch eine Division> zu ersetzen, nur weil der Compiler dann eh wieder einen Shift daraus> macht ;-)
Das ist sicher nicht sinnvoll.
Wie du schon sagtest: Sinnvoll ist es, sich im Kontext klar zu machen,
was die Absicht im Code besser ausdrückt: Shift oder Division und das
dann zu benutzen.
Aber diese "Division ist zu langsam - nimm doch Shift; das zeigt dann
auch noch welch gewaltiger C-Hacker du bist", ich kanns schon nicht mehr
hören.
Im Gegensatz zur vorherigen Funktion (mit der if()-Abfrage) wurden
wieder 6 Byte gespart. (also bereits 12 Byte weniger als die
Ursprüngliche Funktion)
Die Optimierungen sind zwar in diesem Fall sinnlos, da es lediglich ein
Programm zum Testen einer TWI-Verbindung (und Ausgabe der empfangenen
Bytes) ist, Aber mich interessiert, wie ich im Anwendungsfall bestimmte
Operationen möglichst effizient lösen kann.
Um mal eine Meinung zur Diskussion abzugeben:
Ich finde die Schreibweise mit dem Shift-Operator deutlich sinnvoller,
als die Division durch 2. (Selbst wenn es vom Compiler gleich übersetzt
wird)
Dazu hätte ich eine Frage:
Zum Register beschreiben wird doch meist:
1
REGISTER|=(1<<BITX);//Beispiel
verwendet.
Ergibt das nach dem Kompilieren nicht 2 Operationen?
(1) shift
(2) Register beschreiben
oder optimieren die Compiler das automatisch dazu:?
1
REGISTER=0b00010000//Beispiel
(Anmerkung: habe bisher kein Assembler programmiert - und daher auch
keine Ahnung, wie bestimmte Befehle übersetzt werden.
Aber das folgt in den nächsten Monaten noch)
@Erik Her (agutanus)
>oder optimieren die Compiler das automatisch dazu:?>REGISTER = 0b00010000 //Beispiel
Ja, denn das Schieben besteht komplett aus Konstanten, das macht der
Compiler vorher.
MfG
Falk
> verwendet.> Ergibt das nach dem Kompilieren nicht 2 Operationen?> (1) shift> (2) Register beschreiben>
Der Shift wird optimiert, da ja alle Bestandteile konstant sind und
damit kann der Compiler den Wert selber ausrechnen.
> oder optimieren die Compiler das automatisch dazu:?>
1
REGISTER=0b00010000//Beispiel
Das ist aber eine andere Operation :-)
Oder hast du hier nur das |= vergessen?
ich habe das | vergessen.
im folgenden Beitrag habe ich das (1<<PIN4) vergessen.
-> ich konnte meine eigenen Beiträge nicht mehr bearbeiten, da bereits
Antworten geschrieben wurden...