PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : #C pointer wird überschrieben :-(


Cpl. Dwayne Hicks
2010-06-01, 07:03:54
Hi!

Ich benutze den CC5X compiler um einen kleinen 8 bit PIC microcontroller zu programmieren. Das Program soll eine DS1307 Uhr auslesen über den I2C bus.


In dieser function returne ich den pointer, soweit so gut.


uns8 readtime(void)
{

static uns8 seconds, tseconds, minutes, tminutes, hours, thours;
uns8 *ptr, add;


start();
TX8(0xd0);
TX8(0x00);
start();
TX8(0xd1);
seconds=RX8();
start();
TX8(0xd0);
TX8(0x01);
start();
TX8(0xd1);
minutes=RX8();
start();
TX8(0xd0);
TX8(0x02);
start();
TX8(0xd1);
hours=RX8();



seconds=0xf1;
minutes=0xf5;
hours=0xff;

tseconds=seconds&0xf0;
tminutes=minutes&0xf0;
thours=hours&0xf0;


ptr=&add;
*ptr=tseconds;
ptr++;
*ptr=seconds&0x0f;
ptr++;
*ptr=tminutes;
ptr++;
*ptr=minutes&0x0f;
ptr++;
*ptr=thours;
ptr++;
*ptr=hours&0x0f;

return ptr;


bloß wenn ich den pointer dann an die nächste function weiterleite wird der inhalt der ersten pointer adresse wieder überschrieben. Ich hab mal die file register beim debuggen beobachtet und das passiert immer genau dann wenn er beim ersten "if" unten ankommt.
Dabei wird was auch immer in "init" enhalten ist in die adresse kopiert.

uns8 display(uns8* time, uns8 init)

{


static uns8 lin, pos;






if (init==1)
{
lin=0;
pos=0;
}


time-=4;
send_byte(*time,1,1);




}



meine mainline sieht so aus:

void main(void)
{

bit runonce =0;
uns8* time;

setup();
setup_LCD();
delay(50);


while(1)
{
if (runonce==0)
runonce=initialize(0);

while (OSC==0);
{
time=readtime();
display(time,0);
}
}




Also im Prinzip werden alle Inhalte der pointer addressen wieder überschrieben sobald ich in die display funtion reingehe.
Ich bin offensichtlich kein Experte in #C :wink: Hoffentlich kann mir jemand hier helfen. Danke! :smile:

Kann ich dem Pointer array denn keinen eigenen RAM Bereich zuweisen, sodass kein memory hole entsteht?

Gast
2010-06-01, 08:30:22
Schuss ins Blaue, aber wenn Du es mit normalen C vergleichst: du gibts ja eine lokale Variable *ptr zurück, wenn Du aus der Funktion rausgehst ist die nicht mehr gültig - ausserhalb des Scopes. Der Pointer in der main auf time enthält nur Datenmüll.

Möglichkeit a.) übergib den pointer von der main mit in die funktion und beschreibe ihn in der funktion.

Möglichkeit b.) mach auch den *ptr in der Funktion statisch, dann landet der Parameter nicht am Stack.

Ich würd dir aber Möglichkeit a ans Herz legen, ist sauberer.

lg

noid
2010-06-01, 09:09:03
Klassischer Fehler, aber Gast hat das schon schneller erkannt.

Prinzipiell sollte man es wirklich so machen, dass eine Funktion nur mit dem Arbeitet was man ihr gibt - dies sollte man aus Stackspargründen (wenn dieser begrenzt ist) by reference machen, kleine Funktionen sind per Value ok.

Cpl. Dwayne Hicks
2010-06-01, 13:18:01
Danke Leute, ich habe es mit der Moeglichkeit a.) vom Gast nun geschafft!

Nachdem ich 2 Stunden lang einen Fehler gesucht habe der dann ganz woanders lag. :biggrin:

Coda
2010-06-01, 13:43:21
Warum "#C"? Das sieht aus wie stinknormales C.

noid
2010-06-01, 14:06:06
Warum "#C"? Das sieht aus wie stinknormales C.

Tippfehler, er schrieb ja nich c#

Zumal er kaum mit c# an einem LCD und lin-bus hantieren wird. Unwahrscheinlich.

Gnafoo
2010-06-01, 14:10:44
Das was du in readtime machst scheint mir aber davon abgesehen aber ziemlich böse zu sein. Du nimmst den Zeiger auf add und weist etwas zu. Bis dahin ist es okay. Dann inkrementierst du den Zeiger, landest damit in einem Speicherbereich, den du nicht reserviert hast und machst eine erneute Zuweisung. Das kann alles mögliche auf dem Stack überschreiben. Lokale Variablen, Rücksprungadressen etc.

Was du wohl eher willst ist ein Array der passenden Größe, anstatt add, das von außen an die Funktion übergeben wird.

Aus dem time -= 4 in display werde ich übrigens auch nicht so recht schlau. Das ist doch wieder undefinierter Speicher, auf den du da zugreifst. Und die anderen in readtime geschriebenen Werte verwendest du gar nicht. Gut vermutlich ist display in der Form noch nicht vollständig, aber der ungültige Speicherzugriff bleibt.

Cpl. Dwayne Hicks
2010-06-01, 14:26:44
hmmm ich dachte wenn die variable "static" ist dass der Speicherplatz dann sozusagen fest reserviert ist?
Das wuerde doch keinen sinn machen wenn die von einer andren function wieder ueberschrieben werden koennte.
Aber wiegesagt: ich bin Anfaenger :wink:

Und ja, display war noch nicht fertig.

Das -=4 mache ich weil der pointer nach readtime (und dem ganzen ptr++) auf addresse 0x37 zeigt aber die Werte bei 32 Anfangen... ich weiss es ist wohl nicht ganz sauber, aber ich wollte nur mal ein bisschen rumspielen und die register beobachten, damit ich diese ganze Pointer Geschichte mal schnalle. Also meine Werte von readtime werden durchgaengig von 0x32 bis 0x37 beschrieben... ist das in diesem Fall also Zufall dass da gerade nichts willkuerlich uebrschrieben wurde?



Ich benutze uebrigens MPLAB falls das jemand kennt.

EDIT: Mal eine ganz bloede Anfaenger Frage:
Wenn ein Pointer immer etwas wictiges im stack ueberschreiben kann was fuer ein sinn haben die dann?
Sollte ein pointer quasi immer global sein und mit nur einem wert beschrieben werden?

Das heisst in meinem Fall muesste ich add1 - add6 deklarieren und dann jeweils einen neuen pointer fuer jedes?
Sorry falls das alles etwas kompliziert ist... Fragen ueber Fragen :D

Gnafoo
2010-06-01, 16:19:28
Naja irgendwas wird definitiv überschrieben und damit ist das weitere Verhalten undefiniert. Es wundert mich ein wenig, dass nichts weiter zu passieren scheint. Gut ich kenne mich mit Mikrocontrollern nicht so richtig aus, kann sein, dass der Stack da anders aufgebaut ist und man nur in den unbenutzten Speicher schreibt. Problematisch ist es auf jeden Fall.

Wie dem auch sein, ich würde es in etwa so machen:


void readtime(uns8 buffer[])
{
uns8 seconds, tseconds, minutes, tminutes, hours, thours;
//...

// Alles Zugriffe auf reservierten Speicher.
buffer[0] = tseconds;
buffer[1] = seconds & 0x0f;
buffer[2] = tminutes;
buffer[3] = minutes & 0x0f;
buffer[4] = thours;
buffer[5] = hours & 0x0f;
}

void display(uns8 buffer[])
{
// ...
send_time(buffer[1], 1, 1);
}

int main()
{
// ...
uns8 buffer[6]; // Reserviert 6x uns8
readtime(buffer);
display(buffer);
// ...
}


EDIT: Mal eine ganz bloede Anfaenger Frage:
Wenn ein Pointer immer etwas wictiges im stack ueberschreiben kann was fuer ein sinn haben die dann?
Sollte ein pointer quasi immer global sein und mit nur einem wert beschrieben werden?

Niemand hat gesagt, dass sie das immer tun ;). Das Problem hier sind Zeiger auf Dinge die im Stack liegen (sprich: lokale Variablen) und die man in der Aufrufhierarchie nach oben weitergibt. Sobald man nämlich die aktuelle Funktion verlässt, werden die Werte auf dem Stack ungültig. D. h. sie bleiben zwar zunächst da, werden aber überschrieben, wenn der Speicher anderweitig gebraucht wird (üblicherweise beim nächsten Funktionsaufruf).

Das andere Problem ist, dass du einen Zeiger auf eine Variable nimmst und damit arbeitest, als sei es ein Array. "uns8 add;" ist eben nur genau ein uns8-Wert. Wenn du 6 davon haben willst, musst du "uns8 buffer[6]" schreiben. Dann kannst du auch mit Zeigern darauf arbeiten, wie du es getan hast (solange du innerhalb der 6 Einträge bleibst). In diesem Fall ist buffer sogar schon ein Zeiger (uns8[] ist im Prinzip nur syntaktischer Zucker für uns8*), d. h. "*buffer = 0; buffer++; *buffer = 2;" wäre hier auch vollkommen in Ordnung.

Das heisst in meinem Fall muesste ich add1 - add6 deklarieren und dann jeweils einen neuen pointer fuer jedes?
Sorry falls das alles etwas kompliziert ist... Fragen ueber Fragen

Auch das wäre möglich, wenn du die Variablen in der main deklarierst und die Zeiger dann (in der Aufrufhierarchie nach unten) an readtime übergibst. Das heißt aber, du musst 6 Parameter übergeben, denn ptr++ kannst du in diesem Fall nicht machen, schließlich garantiert dir keiner, dass die Variablen auch nebeneinander stehen. Diese Garantie bekommst du nur beim Array, was letztlich auch deutlich einfacher zu schreiben ist (okay ich bin hier etwas ungenau, mit einer Struktur geht das z. B. auch, wäre aber eine relativ hässliche Angelegenheit).