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!
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.
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!
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.
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"
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...
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.
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.
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?
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.
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
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
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.
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 :-)