Hallo, ich bin absoluter Neuling in Sachen C-Programmierung. Ich bin bereit auch ein bisschen dafür zu arbeiten und lese in Büchern, stöbere in allen Foren herum und lasse nichts aus, was Infos bringt. Nun hab ich mich an mein erstes Projekt herangetraut und komm nicht richtig weiter. Als Prozessor habe ich den ATMega8. Mein Problem: Ich möchte innerhalb des Programmes eine Variable festlegen, die für mehrere Funktionen erreichbar sein soll. Ändert eine der Funktionen diese Variable, müssen die anderen auch später noch darauf zugreifen können. ich schreibe also "uint8_t Port;", nachdem ich ausserhalb dieses Files nicht darauf zugreife, brauche ich doch wohl keine extern. Die Deklaration steht am Anfang des files und nicht in irgendeiner Funktion. Nun übergebe ich die variable an eine Funktion "static void send_Port (Port);"dort wird alles abgearbeitet und kehrt danach zurück. Wenn ich nun mit "Port" wweiterarbeiten will, nimmt er statt dessen wieder sein normales Arbeitsregister, in dem irgendwas steht. Kann mir da einer eine kurze Erklärung abgeben? Wäre mir sehr geholfen damit. Andreas
Ein (minimales) Codebeispiel wäre hilfreich. Es gibt ein paar Dinge, die hier zuschlagen können. Ein IO-Port lässt sich nicht ohne weiteres als Variable benutzen, und die Kommunikation zwischen Interruptroutinen und einem Hauptprogramm braucht auch zusätzliche Vorkehrungen (siehe avr-libc FAQ, Punkt 1).
> ich bin absoluter Neuling in Sachen C-Programmierung. Ich bin > bereit auch ein bisschen dafür zu arbeiten Gut, denn sonst könntest du's gleich vergessen. C muß man schon vernünftig lernen. C ist zware eine einfache Sprache, aber ihre korrekte Anwendung ist ganz und gar nicht einfach. > und lese in Büchern, stöbere in allen Foren herum und lasse nichts > aus, was Infos bringt. Nun hab ich mich an mein erstes Projekt > herangetraut und komm nicht richtig weiter. Das geht wohl den meisten anfangs so. Ist ganz normal. > Als Prozessor habe ich den ATMega8. > Mein Problem: Ich möchte innerhalb des Programmes eine Variable > festlegen, die für mehrere Funktionen erreichbar sein soll. Ändert > eine der Funktionen diese Variable, müssen die anderen auch später > noch darauf zugreifen können. ich schreibe also "uint8_t Port;", > nachdem ich ausserhalb dieses Files nicht darauf zugreife, brauche > ich doch wohl keine extern. Sie ist per default extern. Um das abzuschalten, mußt du noch ein "static" davorhängen. Wenn du ein "extern" davorschreiben würdest, würde das den Namen bekanntmachen, aber nicht den Speicher dafür reservieren. > Die Deklaration Beachte den Unterschied zwischen Deklaration und Definition. Eine Definition ist zwar immer auch eine Deklaration, aber umgekehrt gilt das nicht. Eine Deklaration einer Variablen macht nur den Namen und Typ bekannt, aber reserviert keinen Speicher. Das macht die Definition. > steht am Anfang des files und nicht in irgendeiner Funktion. Also eine globale Variable. > Nun übergebe ich die variable an eine Funktion "static void > send_Port (Port);"dort wird alles abgearbeitet und kehrt > danach zurück. Wenn ich nun mit "Port" wweiterarbeiten will, nimmt > er statt dessen wieder sein normales Arbeitsregister, in dem > irgendwas steht. Kann mir da einer eine kurze Erklärung abgeben? Die globale Variable Port wird "by value" an die Funktion übergeben. Das heißt, daß ihr Wert in das Funktionsargument kopiert wird. Mit anderen Worten: Die Funktion benutzt - und ändert - nur eine lokale Kopie, die beim Verlassen der Funktion aufhört zu existieren. Deshalb ändert sich an der globalen Variable nichts. Eine Lösung wäre, den Port als Rückgabewert aus der Funktion zu holen, also diese so definieren: uint8_t send_Port(); und dann: Port = send_Port(); Falls die Funktion den alten Wert braucht, geht natürlich auch: uint8_t send_Port(uint8_t oldPort); und dann: Port = send_Port(Port); Alternativ kannst du auch einen Zeiger als Parameter nehmen. Damit wird nicht der Wert, sondern die Adresse an die Funktion übergeben. Dadurch kann sie die Variable selbst ändern. Das ginge etwa so: void send_Port(uint8_t* Port) { *Port = neuer_wert; /*...*/ } und dann: send_Port(&Port);
Danke Rolf, aller Anfang ist schwer. Ich denke mal, ich bin nicht der erste, der C im Alleingang angeht. Anfangs holperts noch, aber wenn man seine Codes mit denen von anderen vergleicht, fällt doch irgendwann mal auf, was man weniger elegant als die anderen macht. Ich bleib dran. Deklaration und Definition ist bei mir noch nicht ins Blut übergegangen. Dank dir nochmal für die richtige Erläuterung. Die Sache mit dem Zeiger hab ich noch nicht angegangen. Wenn mein Programm mal laufen sollte, kann ich mir fürs nächste mal überlegen das spaßeshalber einzubauen. An die Möglichkeit, den Wert wieder zurückzugeben, hab ich auch schon gedacht. Vermutlich wirds darauf hinaus laufen. Ich hab wieder was gelernt und danke dir. Andreas ** Jörg Tut mir leid, wenn ich den Namen "Port" etwas dämlich gewählt habe. Ich will damit nicht auf einen IO-Port zugreifen, sondern meine verwendete Variable heißt so ähnlich.
Kann man denn die Varialbe nicht "by reference" übergeben, oder ändert er dann die originale Variable noch immer nicht?
. "Kann man denn die Varialbe nicht "by reference" übergeben, oder ändert er dann die originale Variable noch immer nicht?" Genau das geschieht, wenn ein Pointer auf die Variable übergeben wird, wie Rolf am Ende seines Postings bereits schilderte: "Alternativ kannst du auch einen Zeiger als Parameter nehmen. Damit wird nicht der Wert, sondern die Adresse an die Funktion übergeben. Dadurch kann sie die Variable selbst ändern. Das ginge etwa so: void send_Port(uint8_t* Port) { *Port = neuer_wert; /*...*/ } und dann: send_Port(&Port); (Zitat Rolf Ende) In C++ gibt es dafür noch das Konstrukt der "Referenz", das einem echten Pointer gegenüber den Vorteil bietet, daß keine Nullpointerzugriffe auftreten können. void send_Port(uint8_t &Port) { Port = neuer_wert; /* ... */ } IMHO ein Nachteil ist allerdings, daß beim Aufruf einer solchen Funktion kein Unterschied zum "call by value" zu erkennen ist: send_Port(Wert); Ohne sich den Prototypen der Funktion anzusehen, weiß man also nicht, ob da ein "call by value" oder ein "call by reference" geschieht. Das ist IMHO kein Fortschritt. Allerdings ist das Konstrukt der Referenz ein für das Überladen von Operatoren zwingend erforderliches Sprachkonstrukt, daher muss man damit leben.
> In C++ gibt es dafür noch das Konstrukt der "Referenz", das einem > echten Pointer gegenüber den Vorteil bietet, daß keine > Nullpointerzugriffe auftreten können. Wenn man die Adresse eines existierenden Objekts als Zeiger übergibt, gibt's auch in C keine Nullpointer-Zugriffe. ;-) Dieses Problem hat man erst mit dynamic memory allocation (und dort auch nur, wenn man sie nicht anderweitig ordentlich abfängt), aber dagegen würde auch kein Referenzparameter helfen...
Du hast natürlich -wie so oft- Recht; C erfordert halt eine gewisse Disziplin, die möglicherweise dem einen oder anderen Anfänger schwerfällt. Wenn man ausreichend lange/viel in C programmiert hat, dann sind das alles Dinge, die so selbstverständlich sind wie das Atmen ... C ist eine wundervolle Programmiersprache, sofern man nicht das Pech hat, mit echtem "K&R"-C (vor C89) konfrontiert zu werden.
Hallo, ich seh schon! Ich hab noch einiges zu lernen. Die letzten Beiträge übersteigen momentan noch mein Wissen. Ich habe aber einen Teilerfolg errungen. Mit "volatile" habe ich keine Probleme mehr mit dem überschreiben. Wenn ich mich nicht irre, schreibt er die Variable dann wohl in den Speicher und nicht in ein Register. Ist das so? Schlagt mich nicht, wenn ich hier Blödsinn verkünde. Leider hatte ich noch keine Zeit, das Phänomen im Buch nachzuschlagen. Andreas
> Wenn ich mich nicht irre, schreibt er die Variable dann > wohl in den Speicher und nicht in ein Register. Ist das so? Mehr oder weniger. Der Compiler geht im Normalfall davon aus, daß die Variable nur durch das Programm geändert werden kann. Und "Programm" ist hier nur der normale Programmfluss, denn der Compiler weiß ja nichts von Interrupts und davon, wann die zuschlagen können. Daher kann er bei Berechnungne, wenn genug Register übrig sind, sich den Wert in einem Register merken, statt jedesmal in den Speicher zu schreiben und wieder auszulesen. Unter Umständen kann der Compiler sogar den Speicher weglassen und die Variable nur im Register halten. Das volatile sagt nun, dem Compiler, daß die Variable sich jederzeit unerwartet ändern kann und er die genannten Optimierungen nicht durchführen darf.
Analogie aus dem täglichen Leben!? call by value: Du bekommst ein Fotokopie des Orginals und kannst damit machen was Du willt, das juckt das Orginal nicht die Bohne. call by reference: Du bekommst einen Zettel auf dem steht wo sich das Orginal befindet. Wenn Du wissen willst was dort steht musst Du selbst hingehen und nachsehen. Du kannst somit auch auf dem Orginal rumkrizeln und es verändern. Danach können auch alle anderen die wissen wo sich das Orginal befindet Deine Änderungen sehen. Hier kommt jetzt noch "volatile" ins Spiel. Ist die Variable (das Orginal) nicht volatile, darf sich jeder eine eigene Kopie machen und vertraut darauf dass sich diese solange nicht verändert wie er diese benötigt; Ist die Varaiable volatile deklariert, bedeutet dies explizit, dass deine eigene Kopie warscheinlich nicht aktuell ist, da noch jemand (im Hintergrund) jederzeit am Orginal herumdrehen darf. Du (der Prozesor) musst also jedesmal nachsehen was dort steht bevor Du diese Information verwendest.
Ich schenk' Dir mal einige Buchstaben: iiiiiii O-R-I-G-I-N-A-L, verdammich! Mir wäre das ja peinlich, fortwährend ein so einfaches Wort hartnäckig falsch zu schreiben, aber vielleicht ist das ja cooler Stil.
Der Begriff des Orginals, vom lateinischen Substaniv "origo" abstammend, bedeutet soviel wie Urfassung, Urbild, Stammvater. Unser Fremdwort "Orginal" übersetzt der Duden mit "eigentümlich, durch eine besondere Art auffallender Mensch, Sonderling". icur2cool4me ;-)
Das ist ja nicht zu fassen! Es heisst "Or_i_ginal" und nicht "Orginal". Auch im Duden steht 1. ori|gi|nal <Adj.> [lat. originalis = ursprünglich, zu: origo (Gen.: originis) = Ursprung, Quelle, Stamm, zu: oriri, ... "Orginal" ist dem Duden hingegen unbekannt.
> aber vielleicht ist das ja cooler Stil.
Nein, das ist nur ein ganz normaler Schreibfehler, den Werner jetzt
bestimmt nicht mehr machen wird. Ich finde den Hinweis im Prinzip
korrekt, aber den Ton etwas übertrieben.
----, (QuadDash).
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.