Forum: Compiler & IDEs Wie bekomme ich die Adresse von einem Struct Teil?


von Dirk (Gast)


Lesenswert?

Hallo zusammen,

ich stehe gerade auf dem Schlauch :-/

Ich habe einen Struct:
1
typedef struct
2
{
3
   // weitere Vars...
4
   uint8_t  buffer[512]; // Buffer for the data
5
} FILE;

In der Main wird die Var angelegt und einer Funktion ein Pointer auf 
diese Struktur übergeben:
1
FILE fileA;
2
3
func (&fileA);

Innerhalb dieser Funktion brauche ich einen Pointer (z.B. auf 16 Bit Int 
Zahlen) die in unterschiedlichen Bereichen des Strukturelements "buffer" 
stehen:
1
void func (FILE *file)
2
{
3
 uint16_t *ptr;
4
 uint16_t x = 0;
5
6
 do {
7
   // Code der x verändert
8
9
   ptr = (uint16_t *)&file->buffer[x];
10
11
   if (*ptr == 0)
12
     *ptr = 0xFFF8;
13
14
   // ...
15
 }
16
 while (...)
17
}

Ist diese Zuweisung richtig?
ptr = (uint16_t *)&file->buffer[x];

Steht danach in ptr die Adresse der Speicherstelle [x] vom buffer der 
Variaben fileA?

Ich habe nicht den Eindruck, schliesse aber einen Fehler in einem 
anderen Programmteil nicht aus. Diese Schreibweise wird vom WinARR GCC 
nicht angemeckert, andere die ich ausprobiert habe schon.
Der "->" ist ja nichts anderes als "(*file).buffer", ich will hier aber 
nicht auf den Inhalt zugreifen sondern die Adresse der Speicherstelle 
haben. Eigentlich die Summe aus "file" und dem Offset des 
Strukturelements "buffer" und dem Arrayelement "x".

Vielen Dank!

von Klaus W. (mfgkw)


Lesenswert?

Dirk schrieb:
> Ist diese Zuweisung richtig?
> ptr = (uint16_t *)&file->buffer[x];

Im Prinzip ja.

Es garantiert aber niemand, daß auf jedem System eine uint16_t an einer 
beliebigen Stelle stehen kann.

Bei AVR ja, auf einem PC eher nicht - da muß es eine gerade Adresse 
sein.

Dirk schrieb:
> Diese Schreibweise wird vom WinARR GCC
> nicht angemeckert, andere die ich ausprobiert habe schon.

Mit welchem Fehler?

Wenn es sich bei FILE um das aus stdio.h handelt:
Es geht dich nichts an, was da drin steht.
Du darfst legal nur einen Zeiger auf so etwas halten und verwenden, 
nicht die Interna der Struktur.
Die kann nämlich jeder libc-Programmierer bauen, wie er will.
Und insofern würde ich mich nicht darauf verlassen, daß es da überhaupt 
ein Element buffer gibt, geschweige denn wie groß es ist.

von Dirk (Gast)


Lesenswert?

Hallo Klaus,

danke für deine Aussagen.

Nein, ich verwende nicht die stdio.h bei der FILE Struktur, das ist 
Kreation des Hauses ;-)

Aber richtig, es geht um Dateien lesen von einer SD Karte.
Bisher hatte ich die Version aus der Codesammlung. (Angepasst an meine 
Bedürfnisse, d.h. kleiner Funktionsumfang) Voll funktionsfähig.
Die Änderung jetzt (siehe 
Beitrag "Re: MMC SD library FAT16 FAT32 read write" ) ist darauf 
begründet, dass ich zeitgleich zwei Dateien offen haben will (eine 
lesend, eine schreibend).

Meine Idee war jetzt den "zentralen" Buffer incl. der Filestruktur nach 
"extern" zu verlagern. So muss jede Funktion Speicherplatz für den 
Zugriff liefern und nicht die FAT / File Funktionen. (kein malloc und 
co, alles statisch :o)

Der "buffer" einthält eine Sektor der SD Karte, in diesem Fall gerade 
der erste Sektor der FAT16 Tabelle. Die Funktion soll einen leeren 
Cluster suchen und ihn als belegt markieren, liefert aber eine 
Entlosschleife bei frisch formatierter SD Karte :-(

Vielen Dank!

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Klaus Wachtler schrieb:
> Es garantiert aber niemand, daß auf jedem System eine uint16_t an einer
> beliebigen Stelle stehen kann.
>
> Bei AVR ja, auf einem PC eher nicht - da muß es eine gerade Adresse
> sein.

Nö, der PC hat keine Probleme mit misalignment, anders als z.B. 68K 
oder ARM.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Dirk schrieb:
> Hallo zusammen,
>
> Ich habe einen Struct:
> typedef struct
> {
>    // weitere Vars...
>    uint8_t  buffer[512]; // Buffer for the data
> } FILE;

Warum nicht gleich so?

[code]typedef struct
{
   // weitere Vars...
   uint16_t  buffer[256]; // Buffer for the data
} FILE;


> Ist diese Zuweisung richtig?
> ptr = (uint16_t *)&file->buffer[x];

Hack. Such mal nach "strict aliasing rules"

von Dirk (Gast)


Lesenswert?

Johann L. schrieb:
> Warum nicht gleich so?
>
> [code]typedef struct
> {
>    // weitere Vars...
>    uint16_t  buffer[256]; // Buffer for the data
> } FILE;

Weil die Daten im "buffer" einem Sektor einer SD Karte entsprechen 512 
Byte -> Byteweise gelesen.
Nur in diesem Fall enthalten die Daten die FAT16 Tabelle, da sind 256 
uint16_t drin.
Klar ich könnte die "uint8_t buffer[512]" durch ein Union ersetzten und 
für jeden Inhalt eine Version anlegen. Mal sehen...

von Klaus W. (mfgkw)


Lesenswert?

Dirk schrieb:
> Klar ich könnte die "uint8_t buffer[512]" durch ein Union ersetzten und
> für jeden Inhalt eine Version anlegen. Mal sehen..

Wobei die implizite Annahme, wie die 256 uint16_t über die 512 uint8_t 
gelegt sind, ebenso gut oder schlecht portabel und ebenso legal oder 
illegal ist, wie einfach den Zeiger zu casten.

Also bleibt es halt doch wieder eine Frage des Geschmacks, oder in 
diesem Fall eher des Geruchs.

von Rolf M. (rmagnus)


Lesenswert?

Klaus Wachtler schrieb:
> Dirk schrieb:
>> Klar ich könnte die "uint8_t buffer[512]" durch ein Union ersetzten und
>> für jeden Inhalt eine Version anlegen. Mal sehen..
>
> Wobei die implizite Annahme, wie die 256 uint16_t über die 512 uint8_t
> gelegt sind, ebenso gut oder schlecht portabel und ebenso legal oder
> illegal ist, wie einfach den Zeiger zu casten.

Nicht ganz. In ISO-C ist die union-Variante illegal, der Zeigercast 
nicht.

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


Lesenswert?

Rufus Τ. Firefly schrieb:
> Nö, der PC hat keine Probleme mit misalignment, anders als z.B. 68K
> oder ARM.

Doch, Performanceeinbußen hat er damit auch.   Ein unaligned access
braucht halt zwei Buszyklen, während sonst nur einer nötig wäre.
Interessiert halt bloß kaum jemanden, nehmen wir eben den nächst
schnelleren Prozessor ...

Rolf Magnus schrieb:
> In ISO-C ist die union-Variante illegal, der Zeigercast
> nicht.

Inwiefern?

von Klaus W. (mfgkw)


Lesenswert?

Rolf Magnus schrieb:
> Nicht ganz. In ISO-C ist die union-Variante illegal, der Zeigercast
> nicht.

Auch wenn der Cast an sich legal ist, hilft das nicht davor, daß auf 
manchen Systemen er zur Laufzeit nicht funktionieren kann, z.B. bei 
ungeraden Adressen bei uint16_t (nicht hier das Problem, nur 
prinzipiell).
Insofern riecht die Stelle etwas merkwürdig, egal wie man es macht.

von Dirk (Gast)


Lesenswert?

Dirk schrieb:
> FILE fileA;
>
> func (&fileA);

Hallo zusammen,

ich konnte heute nicht allzuviel Zeit in das Problem investieren.

Ich habe einen halben "Rückschritt" zur alten Version gemacht und die 
"buffer" Variable wieder aus dem "FILE" Struct entfernt und global 
gemacht.
Funktionierte genauso wenig :-(

Wenn ich die "FILE fileA" mit einem volatile versehe und sie global 
(Ausserhalb der main ()) mache, dann funktioniert alles!

Beide Massnahmen jeweils alleine funktionieren nicht.
Ich habe derzeit keine Ahnung warum das so ist.

Gruß Dirk

von Dirk (Gast)


Lesenswert?

Zu schnell gepostet :-)

Auch die Version von ganz oben (mit "buffer" in der FILE Struct) 
funktioniert mit einem globalen "volatile FILE fileA".....

Ideen?

Gruß Dirk

von Rolf M. (rmagnus)


Lesenswert?

Mal so am Rande: Wieviel RAM hat dein AVR eigentlich, und wieviele 
solche Strukturen legst du an?

von Uwe Bonnes (Gast)


Lesenswert?

Um das ganze nicht zur Laufzeit berechnen zu muessen, gibt es das Macro
      size_t offsetof(type, member);
Funktion

von Klaus W. (mfgkw)


Lesenswert?

naja, aber wenn man die Adresse eines Members braucht, wird dann zur 
Laufzeit dieser Offset auch wieder zur Anfangsadresse der struct 
addiert.

Etwas anderes sollte auch nicht herauskommen, wenn man die Adresse des 
Members bildet.

von Dirk (Gast)


Lesenswert?

Rolf Magnus schrieb:
> Mal so am Rande: Wieviel RAM hat dein AVR eigentlich, und wieviele
> solche Strukturen legst du an?

Hi Rolf,

mein AVR (ATmega644P) hat 4kB RAM.
In meiner Testversion habe ich nur eine Struktur angelegt.

Size after:
AVR Memory Usage
----------------
Device: atmega644p

Program:   10098 bytes (15.4% Full)
(.text + .data + .bootloader)

Data:        674 bytes (16.5% Full)
(.data + .bss + .noinit)

Sollte also passen :-)

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.