Hallo,
ich schalte mit der Funktion "Set_Speed" den Clock-Prescaler vom Mega168
und wollte von euch wissen, wie ich den Parameter "speed"
sinnvollerweise deklariere.
ein ganzes Byte scheint mir übertrieben, oder ist das allg. üblich so?
ich dachte an ein "enum" odersowas, fehlt mir aber noch etwas
Erfahrung...
Evtl. lässt sich für "speed" ein einzelnes Bit definieren?
Dann lag ich ja garnicht soo falsch. Ich lass das erstmal so ;-))
Evtl. lass ich mir mal ein Bitfield durch den Kopf gehen. Kann ja sein,
das ich noch mehr solcher Fälle habe.
Alllerdings habe ich gelesen (Suchfunktion verwendet!), das
Funktionsparameter kopiert werden und damit sowieso ein Byte (sogar zwei
siehe unten: "Erweiterung auf int/unsigned"?) drauf geht.
Zitat aus
http://www.schellong.de/c.htm
[Q]
Beim Aufruf werden die Argumentwerte kopiert, und diese Kopien werden an
die Funktion
übergeben.
Argumentwerte sind Objektinhalte oder Objekt-Adressen.
...
Diese Argumentwerte-Kopien (jetzt Parameter) 'gehören' der Funktion und
können innerhalb der Funktion beliebig verwendet - auch verändert
werden, ohne daß die
Argument-Objekte an der Aufrufstelle verändert werden!
Argumentwerte werden mit mindestens int-Breite kopiert.
Das heißt, es findet zuvor nötigenfalls eine Erweiterung auf
int/unsigned statt.
[/Q]
Danke und Gruß
AxelR.
Davon abgesehen, dass Hellmuth Schellong ja nun nicht unbedingt so
die Referenz ist... (der Mann hat in den BSD-Gruppen schon ziemlich
viel, naja, halbgebackene Dinge von sich gegeben), die ,,Kopie''
besteht im Falle eines AVRs aus der Übergabe in Register r24.
> Argumentwerte werden mit mindestens int-Breite kopiert.> Das heißt, es findet zuvor nötigenfalls eine Erweiterung auf> int/unsigned statt.
Das war mal so.
Zu K&R Zeiten als es noch keine Prototypen gab.
Also Ende der 60-er Jahre.
Heutzutage gibt es das nur noch bei variadischen Funktionen
(zb. printf und Konsorten), für die im Prototyp ein ...
vorkommt.
> Dann lag ich ja garnicht soo falsch. Ich lass das erstmal so ;-))
enum ist hier schon eine gute Idee, aber nicht wegen irgendwelcher
Einsparungen, sondern zur Verbesserung der Lesbarkeit des Codes.
> Alllerdings habe ich gelesen (Suchfunktion verwendet!), das> Funktionsparameter kopiert werden und damit sowieso ein Byte (sogar> zwei siehe unten: "Erweiterung auf int/unsigned"?) drauf geht.
So sieht das auf C-Ebene aus. Im Assembler werden sie dann halt in
Register geladen. Das muß aber sowieso getan werden.
Du könntest die Funktions auch inline machen. Gerade obiges Beispiel hat
da ein sehr großes Optimierungspotential. Die Parameterübergabe fällt
dann weg, und falls der Parameter eine Compiler-Konstante ist, fällt
auch die ganze if-Abfrage weg.
Im übrigen möchte ich noch was zur Diskussion stellen:
Das Bitgepfriemel in einem uint8_t
Klar ist es zunächst mal verführerisch, wenn man mehrere
Flags in einen uint8_t zusammenfasst. Wenn man auf den
Speicher angewiesen ist, dann mach das ruhig
#define FLAG1 0x01
#define FLAG2 0x02
#define FLAG3 0x04
#define FLAG4 0x08
uint8_t Flags;
....
if( Flags & FLAG1 )
// Flag1 ist gesetzt
else if( Flags & FLAG2 ) {
// Flag2 ist gesetzt
Flags &= ~FLAG1; // Flag1 rücksetzen
...
etc.
Dadurch nutzt man die Bits in Flags optimal aus.
Aber um welchen Preis? Bei jedem Zugriff, ob Abfrage,
ob Setzen, ob Löschen artet das in einer UND/ODER/NICHT
Orgie aus (ok, etwas übertrieben). Das kostet erstens
Programmspeicher und zweitens Laufzeit.
Wenn also der SRAM Verbrauch nicht wesentlich entscheidend
ist und 3 Bytes mehr nicht wehtun, dann ist
uint8_t Flag1;
uint8_t Flag2;
uint8_t Flag3;
oft die bessere Lösung, da die programmtechnische Verarbeitung
um einiges einfacher ist.
Wie so oft in der Programmierung ist das die berühmte
"Space for Time" Regel. Man erkauft sich Speicherplatz (Space)
mit erhöhter Laufzeit (Time), bzw. umgekehrt kann man
oft die Laufzeit (Time) mit erhöhtem Speicherbedarf (Space)
verringern.
...
>Du könntest die Funktions auch inline machen. Gerade obiges Beispiel hat
da ein sehr großes Optimierungspotential. Die Parameterübergabe fällt
dann weg, und falls der Parameter eine Compiler-Konstante ist, fällt
auch die ganze if-Abfrage weg.
...
wenn die Parameterübergabe wegfallen könte: wäre ja nicht schlecht.
Der Parameter ist keine Compilerkonstante, sondern wird zur Laufzeit
geändert. (nach jedem 16ten Timer0int -> Stromsparen)
die Funktion inline machen - hmm. Muss ich mir wohl mal ansehen(SuFu)
Gruß
AxelR.
Weil die Prozessoren oft eine Instruktion BNE oder ähnlich haben
(Branch if not Equal), hingegen kein Instruktion für Vergleiche auf 1.
Im übrigen empfehle ich folgende Schreibweise:
if (1 == speed)
Besonders für Umsteiger von anderen Programmiersprachen auf C.
Auch ein BNE erfordert normalerweise, dass irgendeine
andere Instruktion vorher die entsprechenden Bits
im Statusregister setzt. Ladeinstruktionen tun dies
normalerweise nicht.
@StinkyWinky
if (1 == speed)
Warum denn das??
If (frau == sieht_gut_aus)
erscheint mir deutlich lesbarer, als
If (sieht_gut_aus == frau).
@all
habe es nun so gelöst:
Ok, ich nehme den kürzeren Code zurück. Ob da nun ein "cpi r24, 0x01;
brne .+12" oder ein "and r24, r24; breq .+12", oder ein "tst r24; breq
.+12"steht, ist tatsächlich egal.
Oliver
Rufus t. Firefly wrote:
> Das mag zwar sein, anständige C-Compiler werfen aber auch im zweiten> Falle eine Warnung 'raus. Und die andere Schreibweise ist ... hmpf.
Nur steht einem nicht immer ein solcher zur Verfügung. Ich hab mir diese
Schreibweise vor nicht allzulanger Zeit mal angewöhnt und komme damit
prima klar.
Matthias
Hmm. Dann würde ich ein Werkzeug wie Lint verwenden. Das ist selbst in
den freien Ausführungen gründlicher als die meisten Compiler; richtig
scharf wird PC-Lint von Gimpel, aber das kostet auch etwas Geld.
Meine persönliche Meinung:
Wenns jemandem hilft soll ers verwenden. Ich persönlich mags
nicht, für meinen Geschmack stört es den Lesefluss.
Es gibt Ding, die 'macht man' nach einiger Zeit als C-
Programmierer einfach nicht mehr. Das visuelle System ist darauf
trainiert solche Dinge sofort zu sehen. Das ist das gleiche wie
mit for-Schleifen. Solange die in der Form
for( i = 0; i < irgendwas; ++i )
im Text stehen, denkst du nicht mehr drüber nach. Sobald es
aber eine Abweichung von diesem Muster gibt (insbesondere beim
Vergleich), schreit das visuelle System 'Feuer'.
Bei
if( irgendwas = wasanderes)
ist es genau das gleiche. Irgendwann hat man den Punkt erreicht,
an dem sowas beim Schreiben einfach 'seltsam' aussieht.
Ich kann mich ehrlich nicht errinnern, wann ich diesen Fehler
zuletzt gemacht hätte. Muss schon mehr als 10 Jahre her sein.
>Ich kann mich ehrlich nicht errinnern, wann ich diesen Fehler>zuletzt gemacht hätte. Muss schon mehr als 10 Jahre her sein.
Entweder schlechtes Gedächtnis oder "Geiler Macker"...
Du hast aber recht, nur ist bei manchen, die vielleicht nicht ganz so
viel programmieren, zwar das Gefühl (Magengegend) da, dass da etwas
nicht stimmt, aber die entsprechende Reaktion wird (noch) nicht
ausgelöst.
>Und die andere Schreibweise ist ... hmpf.
"hmpf" = "Puääbäh!" ?
>if (1 == speed)
Das stösst mir auch immer sauer auf, wenn ich sowas lesen muß...
Rahul, der Trollige wrote:
>>Ich kann mich ehrlich nicht errinnern, wann ich diesen Fehler>>zuletzt gemacht hätte. Muss schon mehr als 10 Jahre her sein.>> Entweder schlechtes Gedächtnis oder "Geiler Macker"...
Im Ernst. Irgendwann macht man das nicht mehr.
Ist so wie
while( hdhdfkj );
Auch ein beliebter Fehler.
Ich habe für mich vor Jahren umgestellt, dass der ;, selbst
wenn ich ihn haben möchte, auf jeden Fall in eine neue
Zeile kommt
while( jhdfdf )
;
Seitdem ist mir ein versehentlicher ; an dieser Stelle nie
wieder passiert.
>>if (1 == speed)> Das stösst mir auch immer sauer auf, wenn ich sowas lesen muß...
In einem anderen Thread habe ich Folgendes gesehen:
if(wert<1||-1>wert)
abgesehen davon, dass ich da erst mal ein paar Leerzeichen
einfügen muss, hab ich persönlich ein Problem mit der
Schreibweise.
Ich geh nach der Devise vor: "Say what you mean"
Hier soll geprüft werden, ob ein Wert ausserhalb eines Bereichs
ist. Da denke ich aber sofort: Ein Bereich hat eine untere
grenze und eine obere Grenze. Um ausserhalb zu sein, muss
der Wert entweder kleiner als die untere Grenze oder
größer als die obere Grenze sein. Und diesen Gedankengang
setzte ich dann 1:1 in Code um
if( Wert < untere_Grenze || Wert > obere_Grenze )
Andere Programmierer sehen das anders. Die bauen sich
da so eine Art visuelle Hilfe ein
if( Wert < untere_Grenze || obereGrenze > Wert )
Da ist jetzt visuell sichtbar, dass der Wert jeweils
links oder rechts vom Breich sein muss, damit die Bedingung
wahr ist. Bzw. anders rum:
if( untere_Grenze > Wert && Wert < obereGrenze )
Jetzt wird der Wert von den Grenzen quasi eingerahmt und
das symbolisiert, dass auf innerhalb des Bereichs getestet
werden soll.
Ich denk mir dann: Jeder wie er meint. Letztendlich geht es
bei solchen Dingen um persönliche Vorlieben. Ist ein bischen
so wie der Glaubenskrieg wo man denn die { } hinmacht.
Das wichtigste ist immer noch: Entscheide dich für eine
Schreibweise und zieh sie konsequent durch.