Hallo zusammen, ich bin (außer als Leser) neu hier und wie es ausschaut immer noch Anfänger - wenn auch nicht mehr ganz so blutüberschmiert :D Ich übe gerade den Umgang mit ATmegas am Beispiel der Luftfeuchtigkeitssensoren DHT11/22, und mein Code macht mich noch wahnsinnig. Hab schon eine Nacht hinter mir ;) Deswegen möchte ich gern eine Frage zu einem der Probleme loswerden: Ausgangslage: * der Code, der den Sensor auslesen soll, ist in einer Lib * die binde ich vom separaten Hauptprogramm dann ein und linke das Ganze zusammen * zum Debuggen möchte ich Arrays mit Statusinformationen innerhalb einer Bibliotheksfunktion schreiben, die Arrays sind in der Bibliothek definiert Das Problem: Aus blanker Naivität wollte ich nun vom Hauptprogramm aus direkt auf die Arrays zugreifen. Also: extern uint8_t * array1; // usw. deklariert und los gehts. Allerdings geht es schief. Lesezugriffe ergeben irgendwas und ein testweiser Schreibzugriff führt ins Nirvana. Was genau passiert hier? Wie kann man das korrekt lösen? (Außer halt die Datenausgabe auch gleich in eine Lib-Funktion zu packen - ich will LERNEN!) Übrigens: mir ist schon klar, dass da diverse Bibliotheken für die DHT11/22 existieren. Aber wie gesagt, dass ganze ist für mich auch und nicht zuletzt eine Übung. Daher: Ausweichen auf eine existierende Lib kommt nicht in Frage :D Grüße von der zugefrorenen Havel und schon mal vielen Dank an alle Helfer :) Ralph
Ralph K. schrieb: > Aus blanker Naivität wollte ich nun vom Hauptprogramm aus direkt auf die > Arrays zugreifen. Also: > > extern uint8_t * array1; // usw.
1 | extern uint8_t array1[]; |
Stefan Ernst schrieb: > extern uint8_t array1[]; Danke. Aber warum??? Würde das gern im Detail verstehen.
Ralph K. schrieb: > Aber warum??? Würde das gern im Detail verstehen.
1 | extern uint8_t * array1; |
Was sagst du denn dem Compiler damit? Du sagst, dass an der Adresse "array1" ein Pointer liegt, der auf ein uint8_t zeigt. Wenn als Array interpretiert (array1[x]), ist es halt ein Pointer auf das erste Element. Und, spiegelt das deine Situation wieder? Nein, denn du hast an der Adresse "array1" ja keinen Pointer auf das Array, sondern das Array selber. Entgegen dem, was manche Möchtegern-Experten gerne predigen, ist ein Array nun mal eben nicht immer äquivalent zu einen Pointer auf das erste Element.
Stefan hat schon alles Wesentliche gesagt. Hier sind noch ein paar zusätzliche Hinweise: Generell sollte eine Extern-Deklaration genauso aussehen wie die ursprüngliche Variablendefinition, nur eben mit dem Zusatz "extern". Wenn in der Bibliothek also steht:
1 | uint8_t array1[9]; |
dann sollte in den anderen Modulen, die diese Variable verwenden,
1 | extern uint8_t array1[9]; |
stehen. Jetzt ist es aber so, dass der Compiler die Arraygröße nur in der Variablendefinition braucht, nämlich um eine passendes Stück Speicher dafür zu reservieren. Bei bloßen Zugriffen auf das Array ist diese Information uninteressant, da in C keine Überprüfung der Array-Grenzen erfolgt. Also kann man die Größe genauso gut weglassen und schreibt einfach
1 | extern uint8_t array1[]; |
Es ist aber falsch, zu schreiben
1 | extern uint8_t *array1; |
denn ein Pointer ist nicht das Gleiche wie ein Array, auch wenn in vielen Fällen (z.B. bei den Funktionsargumenten) ein Array durch einen Pointer auf sein erstes Element ersetzt wird. In diesem Fall würde der Compiler annehmen, dass in der Bibliothek tatsächlich ein Pointer definiert wurde:
1 | uint8_t *array1; |
Wenn du in deinem Hauptprogramm bspw.
1 | x = array1[4]; |
schreibst, ist das das Gleiche wie
1 | x = *(array1 + 4); |
Da array1 fälschlicherweise als Pointer angesehen wird, wird nachgeschaut, was der Inhalt dieser Pointer-Variable ist, d.h. der Array-Inhalt wird als Pointer interpretiert. Da sich ein Pointer auf dem ATmega aus 2 Bytes zusammensetzt, werden also die ersten beiden Bytes des in der Bibliothek definierten Arrays gelesen (array1[0] und array1[1]). Aus diesen wird eine 16-Bit-Speicheradresse gebildet, der Index 4 hinzuaddiert und von der Ergebnisadresse ein Datenbyte in die Variable x gelesen.
1 | x = array1[4]; |
hat somit den gleichen Effekt wie
1 | x = *(uint8_t *)(array1[0] + 256 * array1[1]); |
Das ist aber garantiert nicht das, was du möchtest. Um solche Fehler zu vermeiden, ist es gängige Praxis, dass alle Extern-Deklarationen in ein Header-File geschrieben werden, und dieses Header-File nicht dort includet wird, wo die Variable verwendet wird, sondern auch dort, wo sie definiert wird. Stimmt nun der Typ der Extern-Deklarationen nicht mit dem der Variablendefinition überein, liefert der Compiler eine Fehlermeldung.
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.