Funktion soll Zeiger auf Struct zurück liefern

Gast #5778867
Hallo,

ist sicher für viele trivial aber nicht, wenn man das noch nicht gemacht 
hat.

Ich habe eine Struktur vom Typ

typedef struct {
  byte  hour,
        min,
    alarms;
} __attribute__((packed)) logfile_t;

und einen Array, der aus einzelnen Elementen dieses Type besteht names 
logfile.

Ich möchte diesen Array nun aus einem EEPROM füllen und dabei wenn es 
geht die Funktion selbst als Rückgabewert benutzen. Also nicht wie im 
Beispiel unten eine Zeigerübergabe bei einer void Funktion.

Geht das überhaupt? Und wenn ja wie? Die 3 Bytes des Struct werden 
einzeln aus dem EE gefüllt.
1
/* Liest einen Alarm Datensatz aus dem externen EE aus */
2
void EE_ReadDataSet(logfile_t *ptr, uint16_t nr)
3
{
4
  char *p = (char*)ptr;
5
  uint16_t pos = (nr * sizeof(ptr));
6
  for (int i = pos; i < (pos + sizeof(ptr)); i++) {
7
    *p++ = eeprom.readByte(pos);
8
  }
9
}

Bisher.... hätte aber gerne *p = EE_ReadDataSet(i);
1
/* Externes EE auslesen ins RAM */
2
  logfile_t* p = logfile;
3
        for (int i = 0; i < logCnt; i++) {
4
         EE_ReadDataSet(p++,i);
5
}
Gast #5778889
Nur eine Vermutung, kann das derzeit nicht testen. Kompiliert aber 
durch.
1
/* Liest einen Alarm Datensatz aus dem externen EE aus */
2
logfile_t EE_ReadDataSet(uint16_t nr)
3
{
4
  logfile_t *res;
5

6
  uint16_t pos = (nr * sizeof(res));
7
  for (uint16_t i = pos; i < (pos + sizeof(res)); i++) {
8
      *(char*)res++ = eeprom.readByte(pos);
9
  }
10
  
11
  return (*res);
12
}
Gast #5778946
mh schrieb:

> Christian J. schrieb:
>> Kompiliert aber
>> durch.
>
> Ohne Warnungen?
>
> Christian J. schrieb:
>> *(char*)res++ = eeprom.readByte(pos);
>
> Es wird ein Byte aus dem EEPROM gelesen. Aber an welche Stelle im
> Speicher (RAM/Register) wird das Byte geschrieben?

Das brachte den AVR dann auch zum Absturz, vermutlich weil es irgendwo 
hin geschrieben wurde, wo es nicht hin gehörte.

war inzwischen fleissig, das EE angeschlossen statt "trocken" zu 
programmieren, so funktioniert es. Geht sicher immer noch etwas 
optimaler, wenn man noch mehr castet. Aber der GCC fasst das ohnehin 
alles zusammen.

Denkfehler war auch dass sizeof(res) = 2 ist und nicht 3, wie erwartet. 
Also die Länge des Zeigers und nicht die worauf er zeigt.

1
/* Liest einen Alarm Datensatz aus dem externen EE aus */
2
logfile_t EE_ReadDataSet(uint16_t nr)
3
{
4
  logfile_t res;      // Ergebnis
5
  char *p = (char*)&res;    // Byte-Zeiger auf Ergebnis
6
  uint16_t pos = (nr * sizeof(logfile_t));
7
  
8
  /* Struct einzeln mit Bytes füllen */
9
  for (uint16_t i = pos; i < (pos + sizeof(logfile_t)); i++) 
10
    *p++ = eeprom.readByte(i);
11
  return (res);
12
}
Gast #5778948
Christian J. schrieb:
> /* Liest einen Alarm Datensatz aus dem externen EE aus */
> void EE_ReadDataSet(logfile_t *ptr, uint16_t nr)
> {
>   char *p = (char*)ptr;
>   uint16_t pos = (nr * sizeof(ptr));
>   for (int i = pos; i < (pos + sizeof(ptr)); i++) {
>     *p++ = eeprom.readByte(pos);
>   }
> }

[c]
logfile *EE_ReadDataSet(logfile_t *ptr, uint16_t nr)
{
...
return ptr;
}
Gast #5778954
du brauchst immer speicher schrieb:
> neeee, pointer auf temporäre variable!

Also wie?

Das hier läuft ja.... und wie mit * ?

Oh... wurde ja schon geändert das Posting.... logfile_t *ptr braucht es 
aber nicht im Parametersatz. Ein Datensatz ist eindeutig zu finden über 
seine Nummer und hat die Adresse Nummer * Datensatzgröße.
Gast #5779358
Macht es eigentlich Sinn die Funktionen allgemein gültig zu halten und 
nicht an einen Typ zu binden?

Lässt sich der Hilfszeiger aus dem Cast

char *p = (char*)target;

noch mit dem

*p++ = eeprom.read(target++);

irgendwie verschmelzen?

Gibt ja die abenteuerlichsten * und ** und & Konstruktionen...

1
/* Schreibt einen undefinierten Struct weg */
2
void EE_Ext_WriteData(uint16_t target, void *source, size_t len)
3
{
4
  char *p = (char*)source;
5
  for (uint16_t i = 0; i < len; i++) {
6
    eeprom.write(target++, *p++);
7
  }
8
  
9
}
10

11
/* Beschreibt einen undefinierten Struct mit EE Daten */
12
void EE_Ext_ReadData (uint16_t eesrc, void *target, size_t len)
13
{
14
  char *p = (char*)target;
15
    for (uint16_t i = 0; i < len; i++) {
16
      *p++ = eeprom.read(target++);
17
    }
18
}
Gast #5779937
Christian J. schrieb:
> Macht es eigentlich Sinn die Funktionen allgemein gültig zu halten und
> nicht an einen Typ zu binden?

Wie immer: It depends. Hier im speziellen würde ich statt "void*" ein 
"uint8_t*" nehmen. Erstens, um klar zu machen, dass es Alignment und 
Padding zu beachten gilt wenn man die Funktion nutzt. Zweitens bezieht 
sich die Länge ja auf etwas und in diesem Fall auf Bytes, also uint8_t.

Die Write Funktion kann ein "const void*" Zeiger bekommen.
Gast #5779999
Danke,

ich kriege trotzdem noch die Flöhe, weil das falsche drin steht :-(((
Mann, so schwer ist das doch nicht. Das EE lässt sich einwandfrei 
beschreiben in for Schleifen. Das ist also schon mal ok. Aber der Rest 
ist Murks.
1
Aufrufe:
2
EE_Ext_WriteData(logCnt-1, (uint8_t*)&logfile[logCnt-1],sizeof(logfile_t));
3
      EE_Ext_ReadData(logCnt-1,(uint8_t*)&logfile[logCnt-1],sizeof(logfile_t));
4

5

6
/* Schreibt einen undefinierten Struct weg */
7
void EE_Ext_WriteData(uint16_t target, uint8_t *source, size_t len)
8
{
9
    for (uint16_t i = 0; i < len; i++) {
10
           eeprom.writeByte(target++, *(source++));
11
    }
12
}
13

14
/* Beschreibt einen undefinierten Struct mit EE Daten */
15
void EE_Ext_ReadData(uint16_t eesrc, uint8_t *target, size_t len)
16
{
17
       for (uint16_t i = 0; i < len; i++) {
18
          *(target++) = eeprom.readByte(i);
19
  }
20
}

Vorher:
19
8
17
Nachher:
19
19
19
Gast #5780006
Christian J. schrieb:
> und dabei wenn es
> geht die Funktion selbst als Rückgabewert benutzen

Hast du deine Anfrage vergessen? Wo sind die Rückgabewerte?

Christian J. schrieb:
> Lässt sich der Hilfszeiger aus dem Cast
>
> char *p = (char*)target;
>
> noch mit dem
>
> *p++ = eeprom.read(target++);
>
> irgendwie verschmelzen?

Ja, typisiere source und target und lass p einfach weg.

Christian J. schrieb:
> char *p = (char*)target;
...
>       *p++ = eeprom.read(target++);

Überlege einmal genau was da passiert und welcher Wert in den Variablen 
steckt. :-<<<

Und gib bitte die Deklarationen der beiden eeprom. Funktionen an.
Beitrag #5780033 wurde von einem Moderator gelöscht.
Gast #5780081
Christian J. schrieb:
> ich kriege trotzdem noch die Flöhe, weil das falsche drin steht :-(((
> Mann, so schwer ist das doch nicht. Das EE lässt sich einwandfrei
> beschreiben in for Schleifen. Das ist also schon mal ok. Aber der Rest
> ist Murks.

Also mich würde schonmal wundern, warum du "eesrc" gar nicht brauchst 
;-)
Gast #5780084
x^y schrieb:
> Also mich würde schonmal wundern, warum du "eesrc" gar nicht brauchst
> ;-)

Das Brett vorm Kopf.... :-) Wenn man zu lange davor sitzt....
1
/* Schreibt einen undefinierten Struct weg */
2
void EE_Ext_WriteData(uint16_t target, uint8_t *source, size_t len)
3
{
4
    for (uint16_t i = 0; i < len; i++) 
5
        eeprom.writeByte(target + i, *(source++));
6
}
7

8
/* Liest einen Struct mit EE Daten zurueck*/
9
void EE_Ext_ReadData(uint16_t eesrc, uint8_t *target, size_t len)
10
{
11
    for (uint16_t i = 0; i < len; i++)
12
       *(target++) = eeprom.readByte(eesrc + i);
13
}

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 7 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.