Forum: Compiler & IDEs return auch mit string?


von Nik Bamert (Gast)


Lesenswert?

Hi!

Ich bin gerade dabei ata routinen für meinen mp3 player zu schreiben.
Nun ist ein sektor ja 512 byte gross, auslesen tue ich jedoch immer nur
32 byte, da ich einen atmega8515(512byte ram) benutze aber
kein externes sram verwenden möchte.

Also dann werde ich eine Funktion haben, die so aussieht wie etwa:

void ReadSector(u32 LBAsect, u16 sectpos)
{

char buffer[32];

.
.
.
return buffer;
}

Kann ich denn die ganzen 32 bytes so über return zurück "senden",
oder ist return eher für bit / byte werte gedach und ich sollte
eher etwas anderes verwenden, wie zum beispiel eine
globale variabe(falls das überhaupt geht)?

Falls das mit return so gehen würde könnte ich das dan ja etwa so
aufrufen:

buffer = ReadSector(200, 64);

und dann müsste rein theoretisch die 32 bytes dann in dem buffer
landen?

Mit der Frage seid ihr sicherlich unterfordert-naja sobald ich das Buch
finde das mir Rufus empfohlen hat werde ich euch nicht mehr mit so
Anfängerfragen nerven..:)

mfg Nik

von OldBug (Gast)


Lesenswert?

>void ReadSector(u32 LBAsect, u16 sectpos)
>{
>  char buffer[32];
>  return buffer;
>}

Das ist nicht möglich, da der Speicher auf den buffer[] Zeigt nach
dem Verlassen der Funktion 'ReadSector' nicht mehr gültig ist (lokale
Variablen existieren auf dem Stack). Am einfachsten sollte es sein, wenn
Du buffer[] global anlegst.

von Nik Bamert (Gast)


Lesenswert?

oops ich wollte die variabel eigentlich nicht zweimal buffer nennen

void ReadSector(u32 LBAsect, u16 sectpos)
{

char buffer[32];

.
.
.
return buffer;
}


daten = ReadSector(200, 64);

so etwa meinte ich das..dass mit return das ganze zurückgegeben wird
und dann nacher in den buffer daten kommt.
Aber dadurch verliere ich wohl sowiso nur unnötig ram.
Also dann doch wohl besser eine globale variabel.
Ich hab schon eine Datei wo ich einige Progmem Strings drinn habe,
kann ich dort auch eifach normale strings definieren, oder braucht es
eine besondere schreibweise?

Ich würde jetzt einfach ausserhalb von einer Funktion
unsigned char buffer[32]; schreiben-wäre das so korrekt?

von OldBug (Gast)


Lesenswert?

>>void ReadSector(u32 LBAsect, u16 sectpos)
>>{
>>  char buffer[32];
>>  return buffer;
>>}
>
>Das ist nicht möglich, da der Speicher auf den buffer[] Zeigt

'buffer' ist eine loakle Variable, und wird auf dem Stack reserviert,
sobald die Funktion aufgerufen wird! Nach dem Verlassen der Funktion
wird automatisch alles, was diese Funktion (inkl. Rücksprungadresse des
Aufrufes) vom Stack weggeputzt! Du erhälst zwar die Adresse, an der vor
wenigen Cycles noch Speicher für 'buffer' reserviert war, aber da
kann schon längst etwas völlig anderes stehen... Manipulierst Du jetzt
noch schön die Inhalte, die die an dieser Adresse gespeichert wurden,
steigt die Wahrscheinlichkeit, daß Dein Programm im Nirvana landet
immens...

von Rufus T. Firefly (Gast)


Lesenswert?

Das geht in die Hose.

  void ReadSector(u32 LBAsect, u16 sectpos)
  {

    char buffer[32];

    .
    .
    .
    return buffer;
  }

- ganz abgesehen davon, daß der Returntyp hier nicht "void", sondern
char* heissen müsste.

Es geht deshalb in die Hose, weil der zurückgegebene Pointer auf nicht
mehr belegten Speicher verweist. "buffer" ist eine automatische
Variable, die auf dem Stack angelegt wird und nur innerhalb der
Funktion gültig ist. Beim Verlassen der Funktion wird der Stack
abgeräumt und der zurückgegebene Pointer weist so ins "leere".

Arrays können nicht einfach einander zugewiesen werden:

  char Array1[20];
  char Array2[20];

  Array1 = Array2;  // das geht nicht

Als Rückgabewert einer Funktion können nur Dinge verwendet werden, die
auch etwas anderem zugewiesen werden können (RValue).

Von den Basisdatentypen (int, char etc.) abgesehen ist das nur noch mit
Strukturen möglich.

  typedef struct
  {
    char Text[20];
  } ineffizient;


  ineffizient Variable1;
  ineffizient Variable2;

  Variable1 = Variable2; // in ANSI-C (C89) zulässig

So wäre eine Möglichkeit die Verwendung einer Struktur anstelle eines
Arrays (die Struktur darf wiederum ein Array enthalten) und die
Rückgabe dieser Struktur:

  ineffizient Funktion(int bla)
  {
    ineffizient Variable;

    // irgendwas machen

    return (Variable);
  }

Das ist eine theoretische Möglichkeit. Wie aber der von mir nicht
ohne Grund verwendete Typbezeichner "ineffizient" nahelegt, ist das
sehr ineffizient - hier müssen nämlich permanent Daten im Speicher hin-
und herkopiert werden.
Ältere Compiler haben derartiges auch gar nicht erst zugelassen (in der
vor-ANSI-C-Zeit).

Wesentlich sinnvoller ist die Verwendung eines Arrays an der Stelle, an
der es gebraucht wird und die Übergabe eines Pointers darauf an alle
Funktionen, die damit arbeiten sollen.

Tja, und den Literaturhinweis haste ja wenigstens schon zur Kenntnis
genommen :-)

von Daniel (Gast)


Lesenswert?

Äh hallo,

es ist IMHO keine gute Idee ATA-Routinen anzulegen, die keinen Status
zurückgeben können. Das heißt, wenn ein Fehler auftrat, dann sollte man
ihn auch erkennen können (wenn man auch nicht darauf reagieren möchte
;-) ).

Daher schlage ich den folgenden Prototypen für eine Funktion vor :

uint8_t ui8ATAReadSector(uint32_t ui32LBA, uint16_t* ui16Buffer,
uint8_t ui8Position, uint8_t ui8WordCount);

Diese FUnktion kann dann aus dem Sektor mit der LBA ui32LBA ab der
Position ui8Position (in 16bit - Words) ab ui8WordCount Words (16bit)
in den Puffer ui16Buffer lesen. Außerdem kann nach dem Lesen noch der
Status des Devices (Harddisk, o.Ä.) ermittelt werden und als
Ergebniswert zurückgegeben werden. So lässt sich feststellen, ob die
Leseoperation überhaupt erfolgreich war.

Dieser Vorschlag kommt nicht von ungefähr. Viel mehr ist es der
Prototyp der ATA-Funktion ReadSectors, wie ich sie verwende. Diese
Funktion realisiert den "Read Sector(s)"-Command (Command-Code 0x20)
in meinen Routinen. Meine bisherigen Bemühungen unterstützen dabei
"Read Sector(s)", "Write Sector(s)" sowie Device-Selection und
Hardware-Resets bei ATA-Festplatten. Zusammen mit einer
schreib-/lesefähigen FAT16/32-Implementation arbeite ich im Moment an
einem MP3-Player (so wie jeder ;-) ). Ich kann mit den genannten
Routinen bisher über Hyperterminal Dateien von der Festplatte auf den
Computer laden, Verzeichnisse und Dateien erstellen, ansehen und durch
das Dateisystem browsen.

MfG, Daniel.

von Nik Bamert (Gast)


Lesenswert?

>Wesentlich sinnvoller ist die Verwendung eines
>Arrays an der Stelle, an der es gebraucht wird und
>die Übergabe eines Pointers darauf an alle Funktionen,
>die damit arbeiten sollen.

Also müsste ich eigentlich nicht die Daten, sondern nur den Pointer
übergeben?
Naja, das mit den Pointern scheint mir immernoch ein wenig fremd,
ich werde es dann warscheinlich doch mit einer globalen Variabel
versuchen, sofern ich das hinkriege :)

>Tja, und den Literaturhinweis haste ja wenigstens
>schon zur Kenntnis genommen :-)

klar doch :) Ich bin nicht der Typ der einfach in ein Forum kommt, um
Fragen zu stellen
ohne vorher zu versuchen sie sich selbst zu beantworten. So habe ich
schon
viel C Sourcecode gelesen(zum Beispiel den von yampp3 & 7).
Allerdings gibt es dort Dinge die ich mir nicht ohne weiteres erklären
kann,
die auch nicht kommentiert sind, weil sie für den Programmierer
selbstverständlich waren denke ich...
Genau mit solchen Sachen habe ich dann Probleme.
Zum Beispiel schon der unterschied von

char buffer[20]; zu
unsigned char buffer[20];

Vergleichbares findet sich in basic kaum und obwohl ich eigentlich
Basic sehr gut beherrsche, muss ich nun in C die Grundlagen wieder
lernen :(


Ach ja, i kann das Buch einfach nicht finden, nicht einmal beim
grössten
onlinebuchhändler den ich kenne. Was heisst denn das k&k
ausgeschrieben.. ;-) ?

von Volkmar (Gast)


Lesenswert?

> Ach ja, i kann das Buch einfach nicht finden, nicht einmal beim
> grössten onlinebuchhändler den ich kenne.

Den Link habe ich Dir in dem anderen Thread schon gegeben.

> Was heisst denn das k&k ausgeschrieben.. ;-) ?

Das heißt nicht k&k sondern K&R. Es sind die Anfangsbuchstaben der
Autoren Brian W. Kernighan und Dennis M. Ritchie.

Volkmar

von Rufus T. Firefly (Gast)


Lesenswert?


von Nik Bamert (Gast)


Lesenswert?

Ich möchte nicht mit unnötig vielen Threads nerven, desshalb nochmals
hier:

Wenn ich einen Integer Wert in 4 bytes umwandeln möchte, geht das dann
auch mit einem shift oder funktioniert das nur innerhalb eines bytes
mit shift?

von Rufus T. Firefly (Gast)


Lesenswert?

Was meinst Du mit "einen Integer Wert in 4 bytes umwandeln"? Könntest
Du das anhand eines Beispiels näher erläutern?

von Nik Bamert (Gast)


Lesenswert?

naja ich habs nun selbst hereausgefunden-das meinte ich :D :

u32 LBA;
u08 byte0, byte1, byte2, byte3;

  byte0 = (u08)(LBA);
  byte1 = (u08)(LBA >> 8);
  byte2 = (u08)(LBA >> 16);
  byte3 = (u08)(LBA >> 24);

LBA ist vorgegeben und daraus rechnet es mir dann die bytes aus.
Hdd Zugriff funzt schon, da mir Fat zu kompliziert ist für den Anfang,
schreibe ich mir warscheinlich ein eigenes Dateisystem.(hab auch schon
genaue Pläne wie)

von Volkmar (Gast)


Lesenswert?

Kennst Du den Begriff 'union'? Damit geht das sehr elegant. Ich
vermute mal, das das hier im Forum schon behandelt wurde, eine Suche
sollte daher erfolgreich sein.

zB hier: http://www.mikrocontroller.net/forum/read-2-13308.html#13331

Volkmar

von Nik Bamert (Gast)


Lesenswert?

ja mit union hab ich ein bisschen herum probiert, aber habs dann
schliesslich doch nicht hinbekommen, dann lass ich es lieber
"unelegant"
;-)

Allerdings muss ich dasselbe nun auch noch rückwärts machen, also ich
lese 4 bytes ein und muss daraus einen integer machen.
Zuerst hab ich an sowas gedacht:

FileSize = (minibuf[30]*65536) + (minibuf[29]*256) + minibuf[28];


(das msb lese ich nicht ein, da es sowiso immer null ist)

es funktioniert teilweise, aber nicht immer, desshalb frage ich mich
obs
mit diesen Shift Befehlen nicht irgendwie einfach ginge(und
richtig)...?

von Peter D. (peda)


Lesenswert?

> ja mit union hab ich ein bisschen herum probiert, aber habs dann
> schliesslich doch nicht hinbekommen, dann lass ich es lieber
> "unelegant"


"unelegant" ist das ganz und gar nicht sondern im Gegenteil
portabel.

Die union-Lösung ist "unelegant", da compilerabhängig, d.h. von der
Byteorder abhängig.


Ich nehme daher auch immer die Schiebe-Lösung, auch wenn die vielleicht
ein paar Zyklen länger dauert.



> es funktioniert teilweise, aber nicht immer

Du mußt die Werte es als unsigned long schreiben und minibuf muß vom
Typ unsigned char sein, sonst kracht es.

FileSize = (minibuf[30]*65536UL) + (minibuf[29]*256U) + minibuf[28];



Peter

von Nik Bamert (Gast)


Lesenswert?

Super, so  läufts :D Tausend Dank

wie müsste ich das denn schreiben wenn ich nun auch noch das msb mit
einberechnen würde?

FileSize = (minibuf[31]*4294967296UL) + (minibuf[30]*65536UL) +
(minibuf[29]*256U) + minibuf[28];

So weit kann ich mir das noch selber denken, aber ist es beim msb dann
sowas sie UD für unsigned double?

von Nik Bamert (Gast)


Lesenswert?

ich hab gerade noch etwas entdeckt...diese eine Zeile benötigt etwa 500
byte programmspeicher-aber ich werde wohl noch einige male so in der
Art etwas umrechnen müssen, habe allerdings nur 8kbyte für das Programm
zur Verfügung...Könnte es nicht irgendwie mit einem Shift gehen?

Ich stelle mir das etwa so vor, dass dem integer zuerst das msb
zugewiesen wird, dann 8 bit shift(welcher richtung weiss ich nicht)
dann das nächste byte addiert wird, wieder shift usw...
Aber ich kann meine Gedanken nicht wirklich in Code umsetzen.. :(

von Peter D. (peda)


Lesenswert?

> diese eine Zeile benötigt etwa 500 byte programmspeicher

ist ja heftig, was für einen Optimierungslevel nimmst Du ?

Versuchs mal so:

FileSize = (minibuf[31]<<24UL) | (minibuf[30]<<16UL) |
(minibuf[29]<<8U) | minibuf[28];


Peter

von Rufus T. Firefly (Gast)


Lesenswert?

.


   FileSize = (minibuf[31]*4294967296UL) + (minibuf[30]*65536UL) +
(minibuf[29]*256U) + minibuf[28];


Der erste Faktor ist etwas zu groß. Nicht 2^32, 2^24 solltest Du
verwenden, also 16777216

  "So weit kann ich mir das noch selber denken, aber ist
  es beim msb dann sowas sie UD für unsigned double?"


Was bitte hat der Datentyp double hier verloren? Du willst doch keine
Floatingpoint-Arithmetik veranstalten!

  uint32_t FileSize;

  uint8_t Byte1;
  uint8_t Byte1;
  uint8_t Byte1;
  uint8_t Byte1;

  FileSize = (Byte1 << 24) + (Byte2 << 16) + (Byte3 << 8) + Byte4;

Oder

  FileSize = (Byte1 * 1677216UL) + (Byte2 * 65536UL) + (Byte3 * 256UL)
+ Byte4;


Natürlich kannst Du das auch so umsetzen, wie Du versuchtest zu
formulieren:

  FileSize = Byte1;

  FileSize <<= 8;

  FileSize += Byte2;

  FileSize <<= 8;

  FileSize += Byte3;

  FileSize <<= 8;

  FileSize += Byte4;

(Anstelle von 'FileSize <<= 8' könnte auch 'FileSize *= 256'
geschrieben werden)


Naja, ob das elegant ist oder in einem halben Jahr beim Durchlesen des
Quelltextes noch verstanden wird ...

von Peter D. (peda)


Lesenswert?

(minibuf[31]<<24UL)

24UL mag im ersten Augenblick unnötig erscheinen, da ja 24 nicht so
groß ist.

Es hat aber doch seinen Sinn, da C eine Operation in dem größten Format
der Operanden ausführt, d.h. es wird damit erzwungen, daß das
Zwischenergebnis unsigned long ist.

Alternativ geht natürlich auch:

((unsigned long)minibuf[31]<<24)


Peter

von Nik Bamert (Gast)


Lesenswert?

hey, ich habs nun endlich irgendwie hinbekommen, vielen Dank an euch
beide :) Was mich aber verwundert, keine der Varianten

  FileSize = (Byte1 << 24) + (Byte2 << 16) + (Byte3 << 8) + Byte4;

oder

FileSize = (minibuf[31]<<24UL) | (minibuf[30]<<16UL) |
(minibuf[29]<<8U) | minibuf[28];

hat funktioniert, auch wenn ich die bytes umgedreht habe, also das lsb
zuerst, bekam ich zwei der bytes richtig raus, aber zwei waren dann
einfach FF...

Dann hab ichs mal so versucht;           FileSize = minibuf[31]; 
FileSize
<<= 8;
FileSize += minibuf[30];  FileSize <<= 8;
FileSize +=minibuf[29];  FileSize <<= 8;
FileSize += minibuf[28];

Und damit hat es dann funktioniert, wer wiso mit den anderen Varianten
nicht...

>Naja, ob das elegant ist oder in einem
>halben Jahr beim Durchlesen des Quelltextes noch verstanden wird ...
Allerdings, aber ich kommentiere solche Stellen gut aus, wenn ich den
Code dann vielleicht mal Online stelle-bis jetzt sieht es nämlich schon
recht gut aus, ich habe gerade mal 512 bytes ram und 8 kbyte fürs
programm. Dabei kann mein Programm bis jetzt das root Directory
mit Fat32 auslesen und anzeigen, und auch schon files
abspielen(allerdings noch nicht mit fat)
So wies aussieht ist das Folgen der Cluster nicht all zu schwer, so
denke ich, dass meine Fat Funktionen am Ende warscheinlich etwa 3 kb
gross sein werden, denn aktuell, wie oben beschrieben ist der code
gerade mal 3.8 kb gross :). Wieviel Ram das ganze in der Fat Funktion
jeweils benötigt, weiss ich nicht, aber ich denke, dass ich alleine für
fat noch unter 100 byte bin.

Nik

von Rufus T. Firefly (Gast)


Lesenswert?

Daß

   FileSize = (minibuf[31]<<24UL) | (minibuf[30]<<16UL) |
   (minibuf[29]<<8U) | minibuf[28];

nicht funktioniert, ist kein Wunder. Die Elemente von minibuf sind vom
Typ uint8_t; wenn man deren Inhalt um mehr als 7 Bits verschiebt, dann
bleibt nichts vom Inhalt übrig.

(@Peter:
Oder wird vom Shift-Operator automatich eine Typerweiterung
durchgeführt?)

Besser wäre ein Typecast, der zunächst uint8_t auf uint32_t erweitert:

  (((uint32_t) minibuf[31])<<24UL)

etc.

von Volkmar (Gast)


Lesenswert?

>  (((uint32_t) minibuf[31])<<24UL)

Und dann würde doch eine 24 anstelle der 24UL reichen, oder?

Volkmar

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.