call by reference für typedef struct

Hallo zusammen,
ich habe lokale typedef struct in setup(), auf die ich von loop() aus per call by reference zugreifen möchte. Wäre die typedef struct als globale variable definiert, also vor setup() wäre der Zugriff ja kein Problem. Aber das ging nicht, weil die Größe erst berechnet werden mußte. Und dies funktioniert erst ab setup().

Hier mein Code:

byte noOfSetBits    = 0;          // Placeholder
const byte bitsSet  =  B00111001; // Set bits)

typedef struct {
  byte byteOne;                   //one byte
  byte byteTwo;                   //one byte
  float floatOne;                 // four bytes
  float floatTwo;                 // four bytes
} STRUCTDEF;                      // Sum = 10 bytes

STRUCTDEF *pstructVar;


void setup() {
  Serial.begin(74880);
  Serial.print("\n\nbitsSet = ");
  Serial.print(bitsSet, BIN);
  Serial.print("\nnoOfSetBits before calculating = ");
  Serial.print(noOfSetBits);
  noOfSetBits = countSetBits(bitsSet); // fill placeholder with actual no of bits set
  Serial.print("\nnoOfSetBits calculated = ");
  Serial.print(noOfSetBits);

  STRUCTDEF structVar[noOfSetBits]; // Allocate mem array of struct
  //pstructVar = &structVar[0];
  pstructVar = structVar;
  Serial.print("\nSize of typedef STRUCTDEF array structVar[] = ");
  Serial.print(sizeof(structVar));
  Serial.print("\nSize of typedef STRUCTDEF array structVar[0] = ");
  Serial.print(sizeof(structVar[0]));

  // fill structVar[]
  for (int i = 0; i < noOfSetBits; i++) {
    structVar[i] = {i, 2 * i, 3 * i, 4 * i};
  }

  Serial.print("\n\nFilled structVar[0] ... [3] in Setup()\n");
  for (int i = 0; i < noOfSetBits; i++) {
    Serial.print(structVar[i].byteOne);
    Serial.print(", ");
    Serial.print(structVar[i].byteTwo);
    Serial.print(", ");
    Serial.print(structVar[i].floatOne);
    Serial.print(", ");
    Serial.println(structVar[i].floatTwo);
  }
}

void loop() {
  Serial.print("\n\nvoid loop(): Size of typedef STRUCTDEF array structVar[] = ");
  Serial.print(sizeof(pstructVar));
  Serial.print("\nvoid loop(): Size of typedef STRUCTDEF array structVar[0] = ");
  Serial.print(sizeof(pstructVar[0]));

  Serial.print("\n\nFilled structVar[0] ... [3] in loop()\n");
  for (int i = 0; i < noOfSetBits; i++) {
    Serial.print(pstructVar[i].byteOne);
    Serial.print(", ");
    Serial.print(pstructVar[i].byteTwo);
    Serial.print(", ");
    Serial.print(pstructVar[i].floatOne);
    Serial.print(", ");
    Serial.println(pstructVar[i].floatTwo);
  }
  while (1);
}

//******* functions *******
int countSetBits(byte number) {
  int result = 0;
  for (int i = 0; i < 8; i++) {
    result += (number & 1);
    number >>= 1;
  }
  return result;
}

Und hier der Ergebnisprint:

bitsSet = 111001
noOfSetBits before calculating = 0
noOfSetBits calculated = 4
Size of typedef STRUCTDEF array structVar[] = 40
Size of typedef STRUCTDEF array structVar[0] = 10

Filled structVar[0] ... [3] in Setup()
0, 0, 0.00, 0.00
1, 2, 3.00, 4.00
2, 4, 6.00, 8.00
3, 6, 9.00, 12.00


void loop(): Size of typedef STRUCTDEF array structVar[] = 2
void loop(): Size of typedef STRUCTDEF array structVar[0] = 10

structVar[0] ... [3] in loop()
0, 0, 0.00, 0.00
26, 1, 0.00, 0.00
1, 19, ovf, ovf
8, 251, 0.00, ovf

Die zweite Tabelle, aus loop() heraus ausgegeben, sollten identische Werte zur ersten aus setup() anzeigen, also:
0, 0, 0.00, 0.00
1, 2, 3.00, 4.00
2, 4, 6.00, 8.00
3, 6, 9.00, 12.00
Tut sie aber nicht!

Was mache ich falsch?

Hilfreiche Tipps wären mir bei meiner Pointerverwirrung sehr hilfreich.

Eigentlich bin ich auf dem Gebiet recht sattelfest...
Aber ich verstehe kein Wort davon, was du da willst....

typedef stammt aus der C Zeit. in C++ brauchen wir das eigentlich nicht mehr

struct STRUCTDEF 
{
  byte byteOne;                   //one byte
  byte byteTwo;                   //one byte
  float floatOne;                 // four bytes
  float floatTwo;                 // four bytes
} ;

STRUCTDEF *pstructVar;

Wenn du einen Zeiger nutzt, solltest du auch Speicher reservieren.

Arbeite doch besser mit Referenzen...
Dann kümmert sich der Kompiler um die Reservierungen.

Ein typedef sorgt für mehr Klarheit bei den Deklarationen. Aber es hilft natürlich nicht bei der Beschaffung von dynamischem Speicher.

Da dynamischer Speicher bei Arduinos kritisch ist, würde ich einfach ein Array mit 8 Elementen statisch anlegen, ausreichend für 8 Bit, und das benutzen.

Bits zählen geht schneller mit x&(x-1), nur mal als Knobelaufgabe für laue Sommerabende :slight_smile:

Ein typedef sorgt für mehr Klarheit bei den Deklarationen.

Ja?
Weiß nicht ....
Bei mir nicht.
Aber Schaden richtet es nicht an.

Aus meiner Sicht hat es historische Bedeutung.
Um alten C++ und aktuellen C Code lauffähig zu halten.

Beispiel:
In der Arduino.h findet sich folgende Zeile:

 typedef uint8_t byte;

Funktioniert, mit jeder (mir bekannten) C und C++ Version
Ist ja auch schon ein paar Jahre alt, der Code.

Ich würde es heute so schreiben:

using byte = uint8_t;

--

typedef class  {} Test;
Test test;

Ist gleichwertig mit:

class Test {} test;

oder

class Test {};
Test test;

Natürlich kann man das auch so schreiben:

typedef class Test {} test;

Sehe aber nicht, wie das irgendwie die Klarheit fördert....
Und häufige meldet der Kompiler dann auch "typedef ignored"
Wenn es sowieso ignoriert wird, dann muss man es auch nicht schreiben.
Faulheit siegt!


Einer der Gründe für die Abschaffung/Ausblendung von typedef ist die "falsche Syntax".
Es sind Quelle und Ziel vertauscht.
Das macht die Sprache unrund.
Ist wenig intuitiv.

typedef altername neuername;
Ein steter Quell für Ärger bei Anfängern.

Bei allen anderen Deklarationen/Definitionen gilt, erst NeuerBezeichner, dann Definition.

Die Verdrehungen von C sind immer ein Ärgernis, nicht nur für Anfänger. Aber noch schlimmer sind die Reparaturversuche der Syntax, die wegen Rückwärts-Kompatibilität zu beliebig vielen verschiedenen aber gleichbedeutenden Konstrukten führen.

Ja, Kompatibilität und Fortschritt sehen oft in Konkurrenz/Widerspruch zueinander.
Das ist nicht nur bei Programmiersprachen so.
Auch: Das können wir hier am grünen Tisch nicht endgültig klären.
Da muss jeder selber wissen was er/sie/es tut.

Da unser fliesskomma offensichtlich keinen der Wege wirklich beherrscht, rate ich dazu erst den moderneren Weg zu lernen.
Weg mit den alten Zöpfen....

Du kannst nicht in setup() lokal ein Objekt erstellen, einen Zeiger darauf abspeichern und dann in loop() darauf zugreifen! Das Objekt hört am Ende von setup() auf zu existieren. Der Zeiger zeigt dann auf ungültigen Speicher.

Um ein Array dynamischer Länge zur Laufzeit zu erstellen musst du mit new Speicher reservieren. Und dann auch wieder freigeben wenn er nicht mehr gebraucht wird!

Aber überlege dir wie gesagt ob es nicht eibe Obergrenze der Anzahl an structs gibt. z.B. ein Array aus 8 und fertig. Und dann abspeichern wie viele tatsächlich verwendet werden.

Bits zählen geht schneller mit x&(x-1), nur mal als Knobelaufgabe für laue Sommerabende :slight_smile:
[/quote]

Stimmt. Danke:
byte countSetBits(byte number) {
int result = 0;
while (number) {
result++;
number &= number--;
}
return result;
}

Hi zusammen,
ich probiers nochmal...
(1)
Im Deklarationsabschnitt gibts eine Bitmaske, deren binäre Quersumme die Größe mehrerer 1D-Arrayobjekte (Im Democode nur 1 Array) bestimmen soll. Die Arrays werden (sollen) in loop() zyklisch mit Daten beschickt.
Das sich die Arrayelemente tatsächlich per Typedef aus mehreren unterschiedlichen Datentypen zusammensetzen, ist eigentlich nebensächlich.
(2)
Die binäre Quersumme wird per Functionaufruf im Setup() berechnet und das Ergebnis in einer globalen Variablen abgelegt.
Im Deklarationsteil sind dererlei Berechnungen ja unmöglich.
(3)
In setup() wird das Array mit der Anzahl von Elementen, entsprechend der binären Quersumme erzeugt.
Und ist laut
@Serenifly
...in loop() wieder futsch. Danke, das war mein Denkfehler.

Aber gibts jetzt eine Lösung für mein Problem, um Speicher zu sparen?
In diesem Projekt liegen die Arraygrößen wirklich nur bei max. 3 x 80 Byte. Und ich könnte, wie von Serenifly vorgeschlagen mit der Max-Größe arbeiten. ...Wenn es auch unelegant ist. Aber für wechselnde Meßtechnikprojekte, mit unterschiedlicher Sensorkombination und -Bestückung, gerate ich schnell ans Speicherlimit und suche eine universelle Lösung.

Irgendwie müßten die Arrays in einer reentanten Function abgelegt werden. grübel
Fällt Euch keine Lösung ein, um diese Abhängigkeiten zu umgehen?

...Ich las gerade vom µControllerparadoxon, Speicher zur Compilezeit reservieren zu wollen, dessen Größe erst zur Laufzeit bekannt wird. Und auch von der wenig idealen Speicherverwaltung derer. Es liest sich eher wenig erfolgversprechend.

while (number) {
  result++;
  number &= number--;
}

So wird das nix :frowning:

Aber vielleicht geht ja
number &= --number;

fliesskomma:
Das sich die Arrayelemente tatsächlich per Typedef aus mehreren unterschiedlichen Datentypen zusammensetzen, ist eigentlich nebensächlich.

Das ist nicht richtig. Die Datenstruktur aus unterschiedlichen Datenelementen wird als struct definiert, typedef ist verzichtbar.

Aber gibts jetzt eine Lösung für mein Problem, um Speicher zu sparen?
In diesem Projekt liegen die Arraygrößen wirklich nur bei max. 3 x 80 Byte.

Wie kommst Du auf diese Zahlen? Das wären ja gleich 3 voll bestückte Arrays.

Man könnte natürlich ein kleineres 1D Array von STRUCTDEFs anlegen, und das gemäß den Anforderungen in mehrere kleine Arrays unterteilen. Dazu sollte für jedes Array die Anfangsadresse (oder Index) und die Anzahl seiner Elemente notiert werden. Eine Fingerübung zur dynamischen Speicherverwaltung :slight_smile:

DrDiettrich:

while (number) {

result++;
 number &= number--;
}



So wird das nix :-(

Aber vielleicht geht ja
number &= --number;

@DrDiettrich
Oh doch!
Ausgeschrieben: number = number & (number - 1)

DrDiettrich:
Das ist nicht richtig. Die Datenstruktur aus unterschiedlichen Datenelementen wird als struct definiert, typedef ist verzichtbar.
Wie kommst Du auf diese Zahlen? Das wären ja gleich 3 voll bestückte Arrays.

Man könnte natürlich ein kleineres 1D Array von STRUCTDEFs anlegen, und das gemäß den Anforderungen in mehrere kleine Arrays unterteilen. Dazu sollte für jedes Array die Anfangsadresse (oder Index) und die Anzahl seiner Elemente notiert werden. Eine Fingerübung zur dynamischen Speicherverwaltung :slight_smile:

DrDiettrich:
Das ist nicht richtig. Die Datenstruktur aus unterschiedlichen Datenelementen wird als struct definiert, typedef ist verzichtbar.
Wie kommst Du auf diese Zahlen? Das wären ja gleich 3 voll bestückte Arrays.

Man könnte natürlich ein kleineres 1D Array von STRUCTDEFs anlegen, und das gemäß den Anforderungen in mehrere kleine Arrays unterteilen. Dazu sollte für jedes Array die Anfangsadresse (oder Index) und die Anzahl seiner Elemente notiert werden. Eine Fingerübung zur dynamischen Speicherverwaltung :slight_smile:

@DrDiettrich

Hier:

typedef struct {
  byte byteOne;                   //one byte
  byte byteTwo;                   //one byte
  float floatOne;                 // four bytes
  float floatTwo;                 // four bytes
} STRUCTDEF;                      // Sum = 10 bytes

3 Arrays á 8 Elementen = 3 x 80 Byte

Ja, OK, dynamische Speicherverwaltung...
Der Code dafür frißt mir aber wieder einen Teil des gewonnen Speichers. Müßte man sich mal überlegen...

Hi

Wenn ich Das jetzt richtig verstanden habe, kann ich überall im Sketch per NEW Speicher reservieren.
Das kannst Du in setup() dann ja machen.
Nun bräuchtest Du nur noch einen globalen Zeiger auf diesen neu erzeugten Bereich / oder eben Mehrere, wenn mehrere Bereiche erzeugt werden sollen.
Denke mir, daß es sinniger ist, mehrere 'Kleine' zu reservieren, als wenige Große.
... wobei so weit vorne im Sketch sollte der Speicher noch aufgeräumt sein - wobei Keiner wirklich weiß, was die ganzen Lib's so treiben.

Ein Freigeben des Speicher muß wohl nicht erfolgen, da die Festlegung bei Programmstart für den Programmablauf festgelegt wird.
(womit der SPeicher freigegeben werden müsste, müsste ich ebenfalls nachlesen - denke, in der Referenz bei new wird man wohl fündig)

MfG

fliesskomma:
@DrDiettrich
Oh doch!
Ausgeschrieben: number = number & (number - 1)

Wenn Du's auf die harte Tour möchtest: ausprobieren und wundern :-]

Lerne den kleinen aber wichtigen Unterschied zwischen --x und x-- verstehen.

@DrDie

Sieh selbst…

void setup() {
  Serial.begin(74880);
  for (int i = 0; i < 256; i++) {
    Serial.print("Dec, Bin, checksum: ");
    decSpaces(i);
    Serial.print(i);
    Serial.print(", ");
    binSpaces(i);
    Serial.print(i, BIN);
    Serial.print(",\t");
    Serial.println(countSetBits(i));
  }
}

void loop() {
}

//******* functions *******
byte countSetBits(byte number) {
  int result = 0;
  while (number) {
    result++;
    number &= number--;
  }
  return result;
}

void decSpaces(int i){
  int j = 100;
  if (i == 0) {
    i++;
  }
  while((j-i)>0){
    j/=10;
    Serial.print(" ");
  }
}
void binSpaces(int i) {
  if (i == 0) {
    i++;
  }
  while (!(i & B10000000)) {
    Serial.print(" ");
    i <<= 1;
  }
}

Und hier ein Teil des Ausducks…

Dec, Bin, checksum:   0,        0,	0
Dec, Bin, checksum:   1,        1,	1
Dec, Bin, checksum:   2,       10,	1
Dec, Bin, checksum:   3,       11,	2
Dec, Bin, checksum:   4,      100,	1
Dec, Bin, checksum:   5,      101,	2
Dec, Bin, checksum:   6,      110,	2
Dec, Bin, checksum:   7,      111,	3
Dec, Bin, checksum:   8,     1000,	1
Dec, Bin, checksum:   9,     1001,	2
Dec, Bin, checksum:  10,     1010,	2
Dec, Bin, checksum:  11,     1011,	3
Dec, Bin, checksum:  12,     1100,	2
Dec, Bin, checksum:  13,     1101,	3
Dec, Bin, checksum:  14,     1110,	3
Dec, Bin, checksum:  15,     1111,	4
Dec, Bin, checksum:  16,    10000,	1
Dec, Bin, checksum:  17,    10001,	2
Dec, Bin, checksum:  18,    10010,	2
Dec, Bin, checksum:  19,    10011,	3
Dec, Bin, checksum:  20,    10100,	2
Dec, Bin, checksum:  21,    10101,	3
Dec, Bin, checksum:  22,    10110,	3
Dec, Bin, checksum:  23,    10111,	4
Dec, Bin, checksum:  24,    11000,	2
Dec, Bin, checksum:  25,    11001,	3
Dec, Bin, checksum:  26,    11010,	3
Dec, Bin, checksum:  27,    11011,	4
Dec, Bin, checksum:  28,    11100,	3
Dec, Bin, checksum:  29,    11101,	4
Dec, Bin, checksum:  30,    11110,	4
Dec, Bin, checksum:  31,    11111,	5
Dec, Bin, checksum:  32,   100000,	1
Dec, Bin, checksum:  33,   100001,	2
Dec, Bin, checksum:  34,   100010,	2
Dec, Bin, checksum:  35,   100011,	3
Dec, Bin, checksum:  36,   100100,	2
Dec, Bin, checksum:  37,   100101,	3
Dec, Bin, checksum:  38,   100110,	3
Dec, Bin, checksum:  39,   100111,	4
Dec, Bin, checksum:  40,   101000,	2
Dec, Bin, checksum:  41,   101001,	3
Dec, Bin, checksum:  42,   101010,	3
Dec, Bin, checksum:  43,   101011,	4
Dec, Bin, checksum:  44,   101100,	3
Dec, Bin, checksum:  45,   101101,	4
Dec, Bin, checksum:  46,   101110,	4
Dec, Bin, checksum:  47,   101111,	5
Dec, Bin, checksum:  48,   110000,	2
Dec, Bin, checksum:  49,   110001,	3
Dec, Bin, checksum:  50,   110010,	3
Dec, Bin, checksum:  51,   110011,	4
Dec, Bin, checksum:  52,   110100,	3
Dec, Bin, checksum:  53,   110101,	4
Dec, Bin, checksum:  54,   110110,	4
Dec, Bin, checksum:  55,   110111,	5
Dec, Bin, checksum:  56,   111000,	3
Dec, Bin, checksum:  57,   111001,	4
Dec, Bin, checksum:  58,   111010,	4
Dec, Bin, checksum:  59,   111011,	5
Dec, Bin, checksum:  60,   111100,	4
Dec, Bin, checksum:  61,   111101,	5
Dec, Bin, checksum:  62,   111110,	5
Dec, Bin, checksum:  63,   111111,	6
Dec, Bin, checksum:  64,  1000000,	1
Dec, Bin, checksum:  65,  1000001,	2
Dec, Bin, checksum:  66,  1000010,	2
Dec, Bin, checksum:  67,  1000011,	3
Dec, Bin, checksum:  68,  1000100,	2
Dec, Bin, checksum:  69,  1000101,	3
Dec, Bin, checksum:  70,  1000110,	3
Dec, Bin, checksum:  71,  1000111,	4
Dec, Bin, checksum:  72,  1001000,	2
Dec, Bin, checksum:  73,  1001001,	3
Dec, Bin, checksum:  74,  1001010,	3
Dec, Bin, checksum:  75,  1001011,	4
Dec, Bin, checksum:  76,  1001100,	3
Dec, Bin, checksum:  77,  1001101,	4
Dec, Bin, checksum:  78,  1001110,	4
Dec, Bin, checksum:  79,  1001111,	5
Dec, Bin, checksum:  80,  1010000,	2
Dec, Bin, checksum:  81,  1010001,	3
Dec, Bin, checksum:  82,  1010010,	3
Dec, Bin, checksum:  83,  1010011,	4
Dec, Bin, checksum:  84,  1010100,	3
Dec, Bin, checksum:  85,  1010101,	4
Dec, Bin, checksum:  86,  1010110,	4
Dec, Bin, checksum:  87,  1010111,	5
Dec, Bin, checksum:  88,  1011000,	3
Dec, Bin, checksum:  89,  1011001,	4
Dec, Bin, checksum:  90,  1011010,	4
Dec, Bin, checksum:  91,  1011011,	5
Dec, Bin, checksum:  92,  1011100,	4
Dec, Bin, checksum:  93,  1011101,	5
Dec, Bin, checksum:  94,  1011110,	5
Dec, Bin, checksum:  95,  1011111,	6
Dec, Bin, checksum:  96,  1100000,	2
Dec, Bin, checksum:  97,  1100001,	3
Dec, Bin, checksum:  98,  1100010,	3
Dec, Bin, checksum:  99,  1100011,	4
Dec, Bin, checksum: 100,  1100100,	3
Dec, Bin, checksum: 101,  1100101,	4
Dec, Bin, checksum: 102,  1100110,	4
Dec, Bin, checksum: 103,  1100111,	5
Dec, Bin, checksum: 104,  1101000,	3
...Schnipp

Dec, Bin, checksum: 250, 11111010,	6
Dec, Bin, checksum: 251, 11111011,	7
Dec, Bin, checksum: 252, 11111100,	6
Dec, Bin, checksum: 253, 11111101,	7
Dec, Bin, checksum: 254, 11111110,	7
Dec, Bin, checksum: 255, 11111111,	8

Ich habe nichts auszusetzen. Dein Tip war hilfreich, denn es spart überflüssige loops.

Dann verhält sich der Compiler noch seltsamer als erwartet. Das -- wirkt sich dann nämlich auf das linke number aus, nicht auf das, wonach es steht.

@Dr.D,
ohne jetzt zu sehr in die Tiefe zu gehen, weil meine Aufgabenstellung an dieser Stelle bereits gelöst ist.
Aber vlt hilft der Blicke auf diesen Link und dieser Demo:

void setup() {
  Serial.begin(74880);
  int y = 0;
  int x = 5;
  int z = 10;
  Serial.print("y = ");
  Serial.print(y);
  Serial.print(", x = ");
  Serial.println(x);

  Serial.print("y = --x;\ny = ");
  Serial.print(y = --x);
  Serial.print(", x = ");
  Serial.print(x);

  Serial.print("\ny = x--;\ny = ");
  Serial.print(y = x--);
  Serial.print(" x = ");
  Serial.print(x);

  y = 0;
  x = 5;
  z = 10;

  Serial.print("\n**********\ny = ");
  Serial.print(y);
  Serial.print(", x = ");
  Serial.print(x);
  Serial.print(", z = ");
  Serial.println(z);

  Serial.print("y = z + --x;\ny = ");
  Serial.print(y = z + --x);
  Serial.print(", x = ");
  Serial.print(x);

  Serial.print("\ny = z + x--;\ny = ");
  Serial.print(y = z + x--);
  Serial.print(" x = ");
  Serial.print(x);

  y = 0;
  x = 5;

  Serial.print("\n**********\ny = ");
  Serial.print(y);
  Serial.print(", x = ");
  Serial.println(x);
  
  Serial.print("y = x + --x;\ny = ");
  Serial.print(y = x + --x);
  Serial.print(", x = ");
  Serial.print(x);

  Serial.print("\ny = x + x--;\ny = ");
  Serial.print(y = x + x--);
  Serial.print(" x = ");
  Serial.print(x);


}

void loop() {

}