Forum: Compiler & IDEs Funktion mit bool als Parameter


von Axel R. (Gast)


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?
1
unsigned char Set_Speed(unsigned char speed)
2
{ 
3
  if (speed == 1){
4
    CLKPR=(1<<CLKPCE);
5
    CLKPR=0x00;
6
    }
7
  else{
8
    CLKPR=(1<<CLKPCE);
9
    CLKPR=(1<<CLKPS2 | 1<<CLKPS1 | 1<<CLKPS0);
10
    }
11
12
}

Danke

AxelR.

von Karl H. (kbuchegg)


Lesenswert?

die kleinste Einheit ist ein Byte. Kleiner geht nicht.

> ein "enum" odersowas

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

von Axel R. (Gast)


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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

von Karl H. (kbuchegg)


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.

von Rolf Magnus (Gast)


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.

von Karl H. (kbuchegg)


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.



von Oliver (Gast)


Lesenswert?

Und wenn du dann noch
1
if (speed)
anstelle von
1
if (speed==1)

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

Oliver

von Rolf Magnus (Gast)


Lesenswert?

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

von Axel R. (Gast)


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.

von StinkyWinky (Gast)


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.

von Karl H. (kbuchegg)


Lesenswert?

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

von Axel R. (Gast)


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:
1
#define CLK_DIV_128 (1<<CLKPS2 | 1<<CLKPS1 | 1<<CLKPS0)
2
...
3
...
4
static inline void Set_Speed_high(void)
5
{ 
6
  
7
    CLKPR=1<<CLKPCE;
8
    CLKPR=0x00;
9
  
10
}
11
12
static inline void Set_Speed_low(void)
13
{ 
14
  
15
    CLKPR=1<<CLKPCE;
16
    CLKPR=CLK_DIV_128;
17
  
18
}

Viele Grüße und schönen Dank

AxelR.

von Karl H. (kbuchegg)


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


von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

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

von Oliver (Gast)


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

von Axel R. (Gast)


Lesenswert?

>beliebten Fehler...

Jetzt habe ich verstanden, was gemeint ist.

von Μαtthias W. (matthias) Benutzerseite


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

von Rufus Τ. F. (rufus) Benutzerseite


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.

von Karl H. (kbuchegg)


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.

von Rahul, der Trollige (Gast)


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ß...

von Werner (Gast)


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
1
if (200 == speed)
]
stehen würde...

von Karl H. (kbuchegg)


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.

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.