mikrocontroller.net

Forum: Compiler & IDEs Funktion mit bool als Parameter


Autor: Axel R. (axelr) Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?
unsigned char Set_Speed(unsigned char speed)
{ 
  if (speed == 1){
    CLKPR=(1<<CLKPCE);
    CLKPR=0x00;
    }
  else{
    CLKPR=(1<<CLKPCE);
    CLKPR=(1<<CLKPS2 | 1<<CLKPS1 | 1<<CLKPS0);
    }

}

Danke

AxelR.

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

Bewertung
0 lesenswert
nicht lesenswert
die kleinste Einheit ist ein Byte. Kleiner geht nicht.

> ein "enum" odersowas

enum ist super. Nur bruacht auch der mindestens ein Byte.

Autor: Axel R. (axelr) Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

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

Bewertung
0 lesenswert
nicht lesenswert
> 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.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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.

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

Bewertung
0 lesenswert
nicht lesenswert
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.



Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und wenn du dann noch
if (speed)
anstelle von
if (speed==1)

schreibst, wird es auch im übersetzten Assmeblercode noch kürzer.

Oliver

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warum? Das würde doch nur einen Test auf Gleichheit mit 1 durch einen 
Test auf Ungleichheit mit 0 ersetzen.

Autor: Axel R. (axelr) Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
...
>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.

Autor: StinkyWinky (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

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

Bewertung
0 lesenswert
nicht lesenswert
Auch ein BNE erfordert normalerweise, dass irgendeine
andere Instruktion vorher die entsprechenden Bits
im Statusregister setzt. Ladeinstruktionen tun dies
normalerweise nicht.

Autor: Axel R. (axelr) Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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:
#define CLK_DIV_128 (1<<CLKPS2 | 1<<CLKPS1 | 1<<CLKPS0)
...
...
static inline void Set_Speed_high(void)
{ 
  
    CLKPR=1<<CLKPCE;
    CLKPR=0x00;
  
}

static inline void Set_Speed_low(void)
{ 
  
    CLKPR=1<<CLKPCE;
    CLKPR=CLK_DIV_128;
  
}


Viele Grüße und schönen Dank

AxelR.

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

Bewertung
0 lesenswert
nicht lesenswert
> if (1 == speed)
>
> Warum denn das??

Weil es dem beliebten Fehler

  if( 1 = speed )

vorbeugt. Obiges ist ein Syntax Error

  if( speed = 1 )

ist keiner


Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das mag zwar sein, anständige C-Compiler werfen aber auch im zweiten 
Falle eine Warnung 'raus. Und die andere Schreibweise ist ... hmpf.

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Axel R. (axelr) Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>beliebten Fehler...

Jetzt habe ich verstanden, was gemeint ist.

Autor: Μαtthias W. (matthias) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

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

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Rahul, der Trollige (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>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ß...

Autor: Werner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>>if (1 == speed)
>Das stösst mir auch immer sauer auf, wenn ich sowas lesen muß...

Das stösst mir auch immer sauer auf. Wenn da
if (200 == speed)
]
stehen würde...

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

Bewertung
0 lesenswert
nicht lesenswert
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.

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.