Forum: PC-Programmierung Richtiger Programmierstil (Klassen)


von Thomas P. (tommy2002)


Lesenswert?

Hallo,

ich habe mal eine Frage zu einem konkreten Beispiel und möchte wissen, 
wie ihr das handhaben würdet. Ich habe eine Klasse und programmiere sehr 
Hardware nah. Zur Zeit läuft die Software auf einem Raspberry PI, jedoch 
würde ich den Code gerne auf einem kleinen ARM Cortex benutzen. Hier 
geht es nun konkret über Klassenvariablen. Wie verwendet man diese 
korrekt und übersichtlich.

Angenommen var1,var2,var3,var4 sind Arrays die jeweils 40 Byte Speicher 
im RAM benötigen (20 x uint16_t). Die Funktion "eineFunktion" wird in 
der Sekunde zwischen 100-500x aufgerufen. Welches Beispiel ist dann 
besser?

Was gehört als Klassenvariable deklariert und was als Funktionsvariable?

Klassenvariable: Das was auch andere Funktionen benötigen könnten?
Funktionsvariable: Belanglose cnt Variablen, nur Variablen die die 
Funktion benötigt, die außerhalb nicht benötigt werden?


EDIT:
Wann macht IHR eine Variable public und wann private?


BEISPIEL A:
1
class EineKlasse
2
{
3
  public:                              
4
  
5
6
    int eineFunktion(void);      
7
8
  private:                          
9
    int eineVariable;
10
};
11
12
int EineKlasse::eineFunktion(void)
13
{
14
int var1=0;
15
int var2=1;
16
int var3=2;
17
int var4=3;  
18
19
var1=var2+var3+var4;
20
return var1;    
21
}


BEISPIEL B

1
class EineKlasse
2
{
3
  public:                              
4
  
5
    int var1=0;
6
    int var2=1;
7
    int var3=2;
8
    int var4=3;  
9
10
    int eineFunktion(void);      
11
12
  private:                          
13
    int eineVariable;
14
};
15
16
int EineKlasse::eineFunktion(void)
17
{
18
var1=var2+var3+var4;
19
return var1;    
20
}


Grüße
Thomas

: Verschoben durch Admin
von Peter II (Gast)


Lesenswert?

Man sollte variabel möglichst nur dort anlegen wo sie gebraucht werden. 
Wenn sie nur in einer Methode verwendet werden dann dort, wenn sie in 
der Klasse gebraucht werden dann dort oder im schlimmsten fall sogar 
global.

Bei Klassen sollte alle Variablen private oder Protected sein. Diese 
werden nur über Methoden geändert. sonst hat man ja nicht die Kapselung 
die man will.

von Waldemar (Gast)


Lesenswert?

int var1=0;
int var2=1;
int var3=2;
int var4=3;


ich habe vor langer Zeit mal gelernt, dass man sowas auch nicht 
unbedingt machen sollte.

Initialisierung und Zuweisung passieren an zwei völlig unterschiedlichen 
Laufstellen, besser wäre folgendes

int var1;
int var2;
int var3;
int var4;

var1=0;
var2=1;
var3=2;
var4=3;

von Waldemar (Gast)


Lesenswert?

*sorry - ersetze Initialisierung durch Deklaration...

von Peter II (Gast)


Lesenswert?

Waldemar schrieb:
> int var1=0;
> int var2=1;
> int var3=2;
> int var4=3;
>
> ich habe vor langer Zeit mal gelernt, dass man sowas auch nicht
> unbedingt machen sollte.

ich glaube sogar das geht in C++ gar nicht, bei C# ist das zulässig.

So macht man es sinnvollerweise:
1
class EineKlasse
2
{
3
  public:                              
4
  
5
    int var1;
6
    int var2;
7
    int var3;
8
    int var4;  
9
10
    int eineFunktion(void);      
11
12
  private:                          
13
    int eineVariable;
14
};
15
16
EineKlasse::EineKlasse()
17
: var1(1),
18
  var2(2),
19
  var3(3),
20
  var4(42)
21
{};

von Thomas P. (tommy2002)


Lesenswert?

Danke für die Antworten, aber um die Zuweisung geht es mir hier nicht. 
Das war nur ein Beispiel. Klar kann man das über den Konstruktor machen. 
Ich wollte nur mal wissen, wie ihr das mit den Variablen Handhabt.

Jetzt wurde angesprochen:

Peter II schrieb:
> Bei Klassen sollte alle Variablen private oder Protected sein. Diese
> werden nur über Methoden geändert. sonst hat man ja nicht die Kapselung
> die man will.

Diesen Vorgang verstehe ich auch nicht so ganz. Welchen Vorteil bringt 
meine eine Memberfunktion, die mir den Inhalt einer Variable ausgibt?
Die brauche ich ja zwingend um den Inhalt einer Variable, die Private 
ist aus der Klasse zu bekommen.

ich könnte machen:

int EineKlasse::getValue()
{
return var1;
}




a=getValue.EineKlasse();

ODER

a=var1.EineKlasse;      <- Das ist doch viel effizienter?

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

Thomas P. schrieb:
> Diesen Vorgang verstehe ich auch nicht so ganz. Welchen Vorteil bringt
> meine eine Memberfunktion,

dann man die Variabel in der Klasse einfach ändern kann und das 
Interface nach außen gleich bleibt.

Wenn du public ist, kann sie auch von außen geändert werden, das will 
man aber nicht.

> a=var1.EineKlasse;      <- Das ist doch viel effizienter?
mit der richtige Optimierung vom Compiler kommt bei beiden das gleiche 
Raus.

von Operator S. (smkr)


Lesenswert?

In deinen beiden Klassen werden komplett unterschiedliche Dinge getan, 
das hat nichts mit public/private zu tun.

Beispiel A:
Hier hast du nur eine public Funktion und eine private Variable welche 
nie verwendet wurde. Die Variabeln var1 bis var4 sind nur innerhalb der 
Funktion gültig und sichtbar, was nichts mit public/private zu tun hat. 
Da diese Variabeln auch nur in der Funktion gültig sind, können sie 
nicht von aussen verändert werden, die Funktion gibt immer den gleichen 
Wert zurück.

Beispiel B:
4 public Variablen, eine public Funktion und wieder eine private 
Variable, welche nie benutzt wird.

Durch eine Instanz der Klasse kannst du auf die Variabeln var1 bis var4 
zugreifen:
1
EineKlasse KonkreteKlasse;
2
KonkreteKlasse.var2 = 12;
3
cout << KonkreteKlasse.eineFunktion() << endl;

Peter II schrieb:
> ich glaube sogar das geht in C++ gar nicht, bei C# ist das zulässig.
>
> So macht man es sinnvollerweise:

+1 für initializer list

von MaWin (Gast)


Lesenswert?

Thomas P. schrieb:
> Angenommen var1,var2,var3,var4 sind Arrays die jeweils 40 Byte Speicher
> im RAM benötigen (20 x uint16_t). Die Funktion "eineFunktion" wird in
> der Sekunde zwischen 100-500x aufgerufen. Welches Beispiel ist dann
> besser?

Deine return var1; geht sowieso nicht mit der Funktionsvariablen, wenn 
das ein Array von 20 Werten ist, denn das Array ist nicht mehr im 
Speicher nachdem die Funktion verlassen wurde. Als einfacher int geht 
das Beispisl schon. Daher ist dein Beispiel völliger Blödsinn zur 
Darstellung der Problematik und du kommst auf völlig falsche Lösungen.

Die Frage ist, wie lange deine Variablen var1, var2, var3 und var4 
gültig sein sollen, und wie viele es davon gibt.

Eine Klassenvariable wie du sie nennst ist so lange gültig wie es die 
Instanz der Klasse gibt (also länger als die Funktion) und es gibt so 
viel davon wie es Instanzen der Klasse gibt. Dafür kostet so eine 
Variable Speicher im RAM von heap.

Eine Funktionsvariable ist nur bis zum Ende der Funktion vorhanden, bei 
Rückkehr aus der Funktion wird sie vergessen, dafür kostet sie RAM im 
stack.

Meine Theorie: Dein Programm hat sowieso nur 1 Instanz der Klasse und 
diese Instanz ist vorhanden vom Programmanfang bis zum Programmende.

Dann stellt sich die Frage, warum es nicht globale Variablen sein 
sollten.
Gibt es IRGEDEINEN realen Grund, warum nicht ?

wenn du mehrere Instanzen der KLasse haben könntet und dann diese 
Variablen 2 3 oder 4 mal da sein müssen -> müssen es Klassenvariablen 
sein.

Wenn die Funktion eineFunktion sich entweder selbst rekursiv aufruft 
oder eventuell simultan in mehreren treads bzw. prozessen parallel 
läuft, muss es eine Funktionsvariable sein.

Wenn es eine Phase im Programm gibt, in der diese Variablen benötigt 
werden (z.B. Datenerfassungsphase), dann aber eine andere Phase im 
Programm gibt, in denen man die Variablen nicht mehr braucht (z.B. 
Datenvisualisierungsphase) aber den Speicherplatz unbedingt für andere 
Variablen benötigt, kann man nicht beide gleichezitig als globale 
Varablen mit einer Gültigkeit von vor dem Programmstart bis nach dem 
Programmende halten.

Wenn weder - noch als Grund dasteht, kann es eine gloabel Variable sein.
Die liegen zwar auch im RAM, müssen aber nicht bei jedem Funktionsaufruf 
alloziert und ggf. initialisiert werden, sie sind gültig und bleiben 
erhalten wenn die Funktion verlassen wird, und da der Speicher schon 
beim Kompilieren reserviert ist kann es damit nicht passieren, daß 
inmiten des Programmlaufs diese Variablen nicht mehr allozierbar sind. 
Kein heap wird benutzt, der stack nicht übermässig aufgebläht und die 
Zugriffe erfolgen an absolute statt relative Adreessen und sind damit 
schneller. Globale Variablen haben also viele vor allem 
Effizienzvorteile, die man nicht ohne Grund herschenken soltle.

Achsoja, dein Prozessor hat eh die 10000-fache Rechenleistung von der 
die nötig ist, also muss amn die auch verblasen....

von JJ (Gast)


Lesenswert?

- Auf var1-4 von außen zugreifen? -> Public. Zugriff über 
Eineklasse::var
- var1-4 nur innerhalb der Klasse benötigt? -> Private
- var1-4 nur innerhalb der Klasse benötigt? -> Private
- var1-4 nur innerhalb von eineFunktion benötigt? -> dort deklarieren
- var1-4 nur innerhalb von eineFunktion benötigt, Werte sollen zwischen 
den Aufrufen erhalten bleiben? -> dort static deklarieren

Hoffe ich erinnere mich richtig. Ist ein bisschen her.
Es gibt noch weitere Möglichkeiten, aber ich glaube das führt zu weit.

von Peter II (Gast)


Lesenswert?

MaWin schrieb:
> Dafür kostet so eine
> Variable Speicher im RAM von heap.

eine Klasse kann doch genauso auf dem Stack liegen.

von Thomas P. (tommy2002)


Lesenswert?

Operator S. schrieb:
> Hier hast du nur eine public Funktion und eine private Variable welche
> nie verwendet wurde.

Ja, habe nie was anderes behauptet

Operator S. schrieb:
> Die Variabeln var1 bis var4 sind nur innerhalb der
> Funktion gültig und sichtbar

Ja, habe nie was anderes behauptet

Operator S. schrieb:
> was nichts mit public/private zu tun hat.

Habe das auch damit nie in den Zusammenhang gebracht

Operator S. schrieb:
> Da diese Variabeln auch nur in der Funktion gültig sind, können sie
> nicht von aussen verändert werden, die Funktion gibt immer den gleichen
> Wert zurück.

Ja auch das hast du vollkommen richtig analysiert gut!

Operator S. schrieb:
> Beispiel B:
> 4 public Variablen, eine public Funktion und wieder eine private
> Variable, welche nie benutzt wird.

Richtig um die private Variable geht auch hier auch nicht.


Ich wollte nur wissen was effizienter ist Beispiel A oder B. Mit der 
Annahme das var1-var4 z.B. große Arrays sind.

MaWin schrieb:
> Deine return var1; geht sowieso nicht mit der Funktionsvariablen, wenn
> das ein Array von 20 Werten ist, denn das Array ist nicht mehr im
> Speicher nachdem die Funktion verlassen wurde. Als einfacher int geht
> das Beispisl schon. Daher ist dein Beispiel völliger Blödsinn zur
> Darstellung der Problematik und du kommst auf völlig falsche Lösungen.

Ich gehe in meinem REALEN Beispiel in eine Funktion und schreibe 20 
Werte in ein Array danach berechne ich den Mittelwert und gebe diesen 
als INT zurück. Das var1-var4 in meinem Beispiel kein Array ist, ist 
völlig klar. Ich hatte jetzt keine lust den 200 Zeilen langen Code zu 
posten, deswegen diese "Vereinfachung"

Meine Frage war nur: Was ist effizienter: Ständig 500 mal in der Sekunde 
neuen Speicher zu reservieren und wieder frei zu geben (Variable in 
Funktion) oder dies einmalig (global)

von Peter II (Gast)


Lesenswert?

Thomas P. schrieb:
> Meine Frage war nur: Was ist effizienter: Ständig 500 mal in der Sekunde
> neuen Speicher zu reservieren und wieder frei zu geben (Variable in
> Funktion) oder dies einmalig (global)

das kann niemand pauschal sagen, auf dem Stack kostet das anlegen von 
variabel keine Zeit.

von Thomas P. (tommy2002)


Lesenswert?

JJ schrieb:
> - Auf var1-4 von außen zugreifen? -> Public. Zugriff über
> Eineklasse::var
> - var1-4 nur innerhalb der Klasse benötigt? -> Private
> - var1-4 nur innerhalb der Klasse benötigt? -> Private
> - var1-4 nur innerhalb von eineFunktion benötigt? -> dort deklarieren
> - var1-4 nur innerhalb von eineFunktion benötigt, Werte sollen zwischen
> den Aufrufen erhalten bleiben? -> dort static deklarieren
>
> Hoffe ich erinnere mich richtig. Ist ein bisschen her.
> Es gibt noch weitere Möglichkeiten, aber ich glaube das führt zu weit.


und

Peter II schrieb:
> Thomas P. schrieb:
>> Meine Frage war nur: Was ist effizienter: Ständig 500 mal in der Sekunde
>> neuen Speicher zu reservieren und wieder frei zu geben (Variable in
>> Funktion) oder dies einmalig (global)
>
> das kann niemand pauschal sagen, auf dem Stack kostet das anlegen von
> variabel keine Zeit.

Bis jetzt die besten Antworten. Danke! Ich denke das kann man 
zusammenfassend so stehen lassen :-)

von Trilobit (Gast)


Lesenswert?

Thomas P. schrieb:
> Ich gehe in meinem REALEN Beispiel in eine Funktion und schreibe 20
> Werte in ein Array danach berechne ich den Mittelwert und gebe diesen
> als INT zurück.

> Meine Frage war nur: Was ist effizienter: Ständig 500 mal in der Sekunde
> neuen Speicher zu reservieren und wieder frei zu geben (Variable in
> Funktion) oder dies einmalig (global)

Dann mache das Array doch statisch in der Funktion.

von Thomas P. (tommy2002)


Lesenswert?

Trilobit schrieb:
> Dann mache das Array doch statisch in der Funktion.

Wäre auch noch eine Option

von Thomas P. (tommy2002)


Lesenswert?

Hier ein Auszug aus meiner Memberfunktion:

Im Prinzip müsste nur intValue nach außen bekannt sein. Also mache ich 
die Public in meiner Klasse
1
uint16_t Channel::readActualCurrent()
2
{
3
  uint16_t offset=25;
4
  uint16_t intValue=0;
5
  uint32_t average=0;
6
  uint16_t var[20]={0};
7
  uint8_t writeBuffer[3]={0};
8
  uint8_t readBuffer[2]={0};
9
  uint8_t cnt=0;
10
11
  for(cnt=0; cnt<20; cnt++)
12
    {
13
      writeBuffer[0]=0x01;
14
      writeBuffer[1]=0xC1;
15
      writeBuffer[2]=0xE3;
16
      i2cWrite(0x48, writeBuffer, 3);
17
18
      while((readBuffer[0] & 0x80)==0)
19
        {
20
          i2cRead(0x48, readBuffer, 2);
21
        }
22
23
      writeBuffer[0]=0x00;
24
      i2cWrite(0x48, writeBuffer, 1);
25
      i2cRead(0x48, readBuffer, 2);
26
      var[cnt]=readBuffer[0] << 8 | readBuffer[1];
27
28
      average=average+var[cnt];
29
      }
30
    average=average/20;
31
    intValue=(((average*0.0001875*1000)-2500)*2)-offset;  //6.144/(2^15-1)=0.0001875
32
33
    return intValue;
34
  }
35
}

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

Thomas P. schrieb:
> Im Prinzip müsste nur intValue nach außen bekannt sein. Also mache ich
> die Public in meiner Klasse

wozu? was gefällt dir an dem return nicht?


Und wie willst du überhaupt ein Methodenmember public machen?

von MaWin (Gast)


Lesenswert?

Thomas P. schrieb:
> Ich gehe in meinem REALEN Beispiel in eine Funktion und schreibe 20
> Werte in ein Array danach berechne ich den Mittelwert und gebe diesen
> als INT zurück. Das var1-var4 in meinem Beispiel kein Array ist, ist
> völlig klar. Ich hatte jetzt keine lust den 200 Zeilen langen Code zu
> posten, deswegen diese "Vereinfachung"

Deine "Vereinfachung" war aber eine "Verunklarung". Offensichtlich 
brauchst du also die 80 Werte mit Beendigung der Funktion nicht mehr. 
Also können es Funktionsvariablen sein. Es gibt keinen sachlichen 
Grund,. warum es Klassenvariablen sein sollten, denn andere 
Klassenfunktionen brauchen die Werte offenbar nicht.

> Meine Frage war nur: Was ist effizienter: Ständig 500 mal in der Sekunde
> neuen Speicher zu reservieren und wieder frei zu geben (Variable in
> Funktion) oder dies einmalig (global)

Wenn die Funktion sowieso lokale Variablen hat, ist es egal, ob da noch 
80 Byte mehr allokiert werden, ob da also ADD StackPointer,5 oder ADD 
StackPointer,80 steht und die ggf. eingeschaltete Stacküberlaufprüfung 
folgt.

Wenn sie keine lokalen Variablen hat (oder so wenige, daß der Compiler 
sie alle in Register wegoptimiert, was er bei den 80 ints im Array nicht 
kann), kostet es mehr Zeit.

Der ZUGRIFF auf die Werte ist bei globalen Variablen an absoluten 
Adressen aber bei quasi allen Prozessoren schneller, manchmal deutlich 
schneller.

Eine Klassenvariable ist aber noch keine globale Variable.

von Thomas P. (tommy2002)


Lesenswert?

Peter II schrieb:
> wozu? was gefällt dir an dem return nicht?
>
> Und wie willst du überhaupt ein Methodenmember public machen?

Ähhh moment! Ja... kleine Änderung
Diese Funktion soll dann 100-500x in der Sekunde aufgerufen werden.

die Variable "current" ist nun eine public Varible der Klasse Channel

1
void Channel::readActualCurrent()
2
{
3
  uint16_t offset=25;
4
  uint32_t average=0;
5
  uint16_t var[20]={0};
6
  uint8_t writeBuffer[3]={0};
7
  uint8_t readBuffer[2]={0};
8
  uint8_t cnt=0;
9
10
  for(cnt=0; cnt<20; cnt++)
11
    {
12
      writeBuffer[0]=0x01;
13
      writeBuffer[1]=0xC1;
14
      writeBuffer[2]=0xE3;
15
      i2cWrite(0x48, writeBuffer, 3);
16
17
      while((readBuffer[0] & 0x80)==0)
18
        {
19
          i2cRead(0x48, readBuffer, 2);
20
        }
21
22
      writeBuffer[0]=0x00;
23
      i2cWrite(0x48, writeBuffer, 1);
24
      i2cRead(0x48, readBuffer, 2);
25
      var[cnt]=readBuffer[0] << 8 | readBuffer[1];
26
27
      average=average+var[cnt];
28
      }
29
    average=average/20;
30
    current=(((average*0.0001875*1000)-2500)*2)-offset;  //6.144/(2^15-1)=0.0001875
31
32
33
  }
34
}

: Bearbeitet durch User
von Bitwurschdler (Gast)


Lesenswert?

Thomas P. schrieb:
> Channel::readActualCurrent()

Ich stolpere immer schwer über solche tolle "Germanismen"

Gemeint ist wohl "akteller Strom", der Englisch sprechende
versteht aber unter "actual" "tatsächlich", wogegen "aktuell"
im Englischen "current" heisst ....

von Thomas P. (tommy2002)


Lesenswert?

Bitwurschdler schrieb:
> Gemeint ist wohl "akteller Strom", der Englisch sprechende
> versteht aber unter "actual" "tatsächlich", wogegen "aktuell"
> im Englischen "current" heisst ....

Jaaaa natürlich hast du recht :-), ich werde mir da was passenderes 
überlegen.

von Thomas P. (tommy2002)


Lesenswert?

MaWin schrieb:
> Deine "Vereinfachung" war aber eine "Verunklarung". Offensichtlich
> brauchst du also die 80 Werte mit Beendigung der Funktion nicht mehr.
> Also können es Funktionsvariablen sein. Es gibt keinen sachlichen
> Grund,. warum es Klassenvariablen sein sollten, denn andere
> Klassenfunktionen brauchen die Werte offenbar nicht.

Ok. Ich dachte dadurch etwas einsparen zu können.

von Slippin J. (gustavo_f)


Lesenswert?

Bitwurschdler schrieb:
> Gemeint ist wohl "akteller Strom", der Englisch sprechende
> versteht aber unter "actual" "tatsächlich", wogegen "aktuell"
> im Englischen "current" heisst ..

Also readCurrentCurrent() ;-)

von Thomas P. (tommy2002)


Lesenswert?

Gustavo F. schrieb:
> Bitwurschdler schrieb:
>> Gemeint ist wohl "akteller Strom", der Englisch sprechende
>> versteht aber unter "actual" "tatsächlich", wogegen "aktuell"
>> im Englischen "current" heisst ..
>
> Also readCurrentCurrent() ;-)

Das dachte ich mir auch :D... Wollte es mir nur verkneifen.

Habe es jetzt readCurrent genannt ;-)

von Slippin J. (gustavo_f)


Lesenswert?

Bitwurschdler schrieb:
> Ich stolpere immer schwer über solche tolle "Germanismen"
>
> Gemeint ist wohl "akteller Strom", der Englisch sprechende
> versteht aber unter "actual" "tatsächlich", wogegen "aktuell"
> im Englischen "current" heisst ....

Ich bin mir gar nicht so sicher, ob 'actual' hier tatsächlich so falsch 
ist. 'actual' bedeutet nämlich 'tatsächlich', 'derzeitig', 
'gegenwärtig', 'effektiv'... Habe auch schon öfter gesehen, dass 
Variablen das im Namen haben.

von Thomas P. (tommy2002)


Lesenswert?


von Frickelfritze (Gast)


Lesenswert?

Gustavo F. schrieb:
> Habe auch schon öfter gesehen, dass Variablen das im Namen haben.

Klar, weil nämlich die Mehrheit der deutschen Programmierer so
stümperhaft Englisch beherrschen.

Ein Amerikaner oder Brite würde das nie so ausdrücken.
Es sei denn es gilt einen "unwirklichen" und einen "tatsächlichen"
Wert zu unterscheiden.

von Frickelfritze (Gast)


Lesenswert?

Frickelfritze schrieb:
> Ein Amerikaner oder Brite würde das nie so ausdrücken.

Und wenn man "aktuell", "gegenwärtig", "laufend" meint stimmt
"actual" überhaupt nicht.

von tictactoe (Gast)


Lesenswert?

Thomas P. schrieb:
> Diese Funktion soll dann 100-500x in der Sekunde aufgerufen werden.
>
> die Variable "current" ist nun eine public Varible der Klasse Channel

Warum? Handelt es sich dabei um einen Zustand, der sich gemerkt werden 
muss? Soweit ich die Funktion überblicke, sehe ich nichts, was 
erfordert, dass sie ein Klassen-Member ist.

von Peter II (Gast)


Lesenswert?

Thomas P. schrieb:
> void Channel::readActualCurrent()
> {
>   uint16_t offset=25;
>   uint32_t average=0;
>   uint16_t var[20]={0};
....
>       var[cnt]=readBuffer[0] << 8 | readBuffer[1];
>       average=average+var[cnt];
>       }
>     average=average/20;
>     current=(((average*0.0001875*1000)-2500)*2)-offset;
> //6.144/(2^15-1)=0.0001875
>   }
> }

wozu überhaupt die var variabel? Wenn du wirklich etwas sparen willst, 
dann lass die Variabel doch ganz weg.

von Thomas P. (tommy2002)


Lesenswert?

tictactoe schrieb:
> Warum? Handelt es sich dabei um einen Zustand, der sich gemerkt werden
> muss? Soweit ich die Funktion überblicke, sehe ich nichts, was
> erfordert, dass sie ein Klassen-Member ist.

Ist auch recht schwer ohne eine Glaskugel, wenn du nicht weißt was der 
Rest von meinem Programm macht.

Ja. Sie speichert den aktuellen Strom. Andere Programmteile können dann 
auf diese Variable zugreifen. Bevor jetzt tausend Leute wieder 
hinterfragen ob das nötig oder unnötig ist, möchte ich alle Zweifel 
beseitigen. Die hälfte des Threads beschäftigt sich sowieso nur mit der 
Sinnigkeit gewisser Formulierungen oder diverser anderer Dinge, die mir 
nicht helfen die Programmierung optimaler zu machen.

Ich habe einige Sensorknoten die ich regelmäßig auslese. Da sich diese 
Sensorknoten nur in der Hardwareadresse unterscheiden, macht es wenig 
Sinn dies ohne Klassen zu lösen. So übergebe ich der Klasse mit dem 
Konstruktor die Hardwareadresse und fertig ist mein Sensor. So kann ich 
dann schnell auf alle Ströme/Spannungen/Temperaturen whatever zugreifen.
1
a=sensor1.current; 
2
a=sensor2.current;
3
a=sensor3.current;
4
a=sensor4.current;
5
a=sensor5.current;
6
7
oder als Get-Funktion
8
9
a=sensor1.getCurrent();
10
...
11
a=sensor5.getCurrent();

Ja? Wäre ohne Klassen bisschen mehr Aufwand...

Da ich mir die Messwerte mit ncurses in der Shell anzeigen lasse, 
rattert im Hintergrund eine Schleife, die mir ständig die Messwerte 
aktualisiert. Darf ich das jetzt weiterhin mit einer Klasse machen? 
Danke :-)

Peter II schrieb:
>> void Channel::readActualCurrent()
>> {
>>   uint16_t offset=25;
>>   uint32_t average=0;
>>   uint16_t var[20]={0};
> ....
>>       var[cnt]=readBuffer[0] << 8 | readBuffer[1];
>>       average=average+var[cnt];
>>       }
>>     average=average/20;
>>     current=(((average*0.0001875*1000)-2500)*2)-offset;
>> //6.144/(2^15-1)=0.0001875
>>   }
>> }

Du hast recht! Ich kann ja auch das machen, was den selben Effekt hat:
1
 void Channel::readActualCurrent()
2
 {
3
   uint16_t offset=25;
4
   uint32_t average=0;
5
   
6
 ....
7
     
8
       average=average+(readBuffer[0] << 8 | readBuffer[1]);
9
       }
10
     average=average/20;
11
     current=(((average*0.0001875*1000)-2500)*2)-offset;
12
 //6.144/(2^15-1)=0.0001875
13
   }
14
}
Ich muss nur aufpassen das die Laufvariable der for-Schleife den selben 
wert die der Teiler durch [average] ist. das werde ich dann noch über 
eine Hilfsvariable lösen.

Danke Peter!!!

von Michael B. (laberkopp)


Lesenswert?

Thomas P. schrieb:
> Da sich diese
> Sensorknoten nur in der Hardwareadresse unterscheiden, macht es wenig
> Sinn dies ohne Klassen zu lösen. So übergebe ich der Klasse mit dem
> Konstruktor die Hardwareadresse und fertig ist mein Sensor. So kann ich
> dann schnell auf alle Ströme/Spannungen/Temperaturen whatever
> zugreifen.

Abenteuerliche Begründung.
Wer nur Nägel kennt, haut auch Schrauben mit dem Hammer rein.

> Ich muss nur aufpassen das die Laufvariable der for-Schleife den selben
> wert die der Teiler durch [average] ist. das werde ich dann noch über
> eine Hilfsvariable lösen.

Ich würde erst mal aufpassen, daß

>      current=(((average*0.0001875*1000)-2500)*2)-offset;
                              ^
da kein float steht, auch nicht 0.1875.

Sondern eher (average*1875)/10000 oder gleich

     current=(((average*1875)/5000)-5000-offset;

Mit unint32_t sollte average ja gross genug sein.
Da kann man, wenn man geschickter formuliert, sicher auch uint16_t draus 
machen.

Es ist ja noch nicht mal klar, ob dein "kleiner Cortex" überhaupt eine 
FPU hätte.


Der Weg, vom ehemals durch Windows, Java, C++ und WebSkripten 
verseuchten Gehirn hin zu effizientem coden ist noch weit...

von Peter II (Gast)


Lesenswert?

Thomas P. schrieb:
> Ich muss nur aufpassen das die Laufvariable der for-Schleife den selben
> wert die der Teiler durch [average] ist. das werde ich dann noch über
> eine Hilfsvariable lösen.

das kann man über ein Define oder eine const int variabel lösen. Wenn du 
die Wahl hast kannst du über 16 werte mitteln, dann kann die Devision 
durch shift (vom Compiler) ersetzt werden.

von Thomas P. (tommy2002)


Lesenswert?

Michael B. schrieb:
> Ich würde erst mal aufpassen, daß
>
>>      current=(((average*0.0001875*1000)-2500)*2)-offset;
>                               ^
> da kein float steht, auch nicht 0.1875.
>
> Sondern eher (average*1875)/10000 oder gleich
>
>      current=(((average*1875)/5000)-5000-offset;
>
> Mit unint32_t sollte average ja gross genug sein.
> Da kann man, wenn man geschickter formuliert, sicher auch uint16_t draus
> machen.

Danke!

> Es ist ja noch nicht mal klar, ob dein "kleiner Cortex" überhaupt eine
> FPU hätte.

Ich möchte auf dem Raspberry so programmieren, dass es mir später leicht 
fallen soll, den Code auf einen µC zu portieren. Zumindest die 
Sensorverwaltung

> Der Weg, vom ehemals durch Windows, Java, C++ und WebSkripten
> verseuchten Gehirn hin zu effizientem coden ist noch weit...

Ja

Peter II schrieb:
> das kann man über ein Define oder eine const int variabel lösen. Wenn du
> die Wahl hast kannst du über 16 werte mitteln, dann kann die Devision
> durch shift (vom Compiler) ersetzt werden.

Vielen Dank!

: Bearbeitet durch User
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.