Moin Moin..
Wo ist eigentlich der Unterschied? Kann es zur Laufzeit Fehler geben?
1
typedefstructtest{
2
Uint8_tvar;
3
}test_t;
4
5
test_t*mit_ptr;
6
test_tohne_ptr;
7
8
voidread(test_t*stru){
9
}
10
11
/* GIBT ES HIER EINEN UNTERSCHIED <- ???*/
12
read(mit_ptr);
13
read(&ohne_ptr);
Kann es zur Laufzeit unterschiede geben? Wenn ich jetzt einen Pointer
übergebe oder mit dem Adressoperator die Adresse vom Struct? Wo ist der
Unterschied?
im Prinzip ist es gleich. Nur ist hier noch ein Fehler drin, das der
Pointer ins "nichts" Zeit. Man muss schon dafür sorgen der der Pointer
wirklich auf eine Variable Zeigt.
Peter II schrieb:> im Prinzip ist es gleich. Nur ist hier noch ein Fehler drin, das der> Pointer ins "nichts" Zeit. Man muss schon dafür sorgen der der Pointer> wirklich auf eine Variable Zeigt.
Wie würde das Aussehen?
Eigentlich ist das nicht gleich.
Im ersten Fall wird eine Kopie von deinem Struct erzeugt und im Falle
des Pointers nicht.
Daten im Struct kannst du also nur mit einem Pointer verändern. Nebenbei
braucht das neu angelegte Struct auch evtl. mehr Platz im Speicher als
ein Zeiger.
"mit_ptr" ist auch nur eine Variable
Ja, eine Adressvariable, semantisch gesehen halt ein Pointer.
Uninitialisiert zeigt es halt irgendwohin*, nicht auf eine vorhandene
Speicherstruktur.
* vermutlich auf Adresse 0, hängt von den verwendeten
Initialisierungsroutinen ab (das was vor der main-Funktion schon
passiert).
>> Was passiert wenn ich es so übergebe? Er muss ja irgendwas falsch machen> dann..
Nach ISO C ist es genau umgekehrt: Er kann nichts falsch machen, denn
jede beliebige Reaktion auf diesen Code gilt als korrekt (Unter der
Annahme, dass read() den Zeiger dereferenziert).
Das nennt sich "undefined behavior" (Undefiniertes Verhalten). Der
Zeiger ist nicht initialisiert, das heißt, es steht irgendeine mehr oder
weniger zufällige Adresse darin. Wenn du den dereferenzierst, ohne ihm
vorher einen gültigen Wert zu geben, rufst du undefiniertes Verhalten
hervor, und dann kann nach ISO C alles passieren.
In der Newsgroup comp.std.c sprach man davon, dass dann Dämonen aus
deiner Nase kommen können (
http://www.urbandictionary.com/define.php?term=nasal%20demons ). Nach
ISO C wäre das tatsächlich eine erlaubte Reaktion auf deinen Code. ;-)
>>>> Was passiert wenn ich es so übergebe? Er muss ja irgendwas falsch machen>> dann..>> Nach ISO C ist es genau umgekehrt: Er kann nichts falsch machen, denn> jede beliebige Reaktion auf diesen Code gilt als korrekt (Unter der> Annahme, dass read() den Zeiger dereferenziert).> Das nennt sich "undefined behavior" (Undefiniertes Verhalten). Der> Zeiger ist nicht initialisiert, das heißt, es steht irgendeine mehr oder> weniger zufällige Adresse darin. Wenn du den dereferenzierst, ohne ihm> vorher einen gültigen Wert zu geben, rufst du undefiniertes Verhalten> hervor, und dann kann nach ISO C alles passieren.> In der Newsgroup comp.std.c sprach man davon, dass dann Dämonen aus> deiner Nase kommen können (> http://www.urbandictionary.com/define.php?term=nasal%20demons ). Nach> ISO C wäre das tatsächlich eine erlaubte Reaktion auf deinen Code. ;-)
Das heißt, würde ich mit einem Pointer auf einem struct arbeiten wollen,
so benötige ich doppelten Speicherplatz?
1
typedefstruct{
2
3
intvar;
4
}test_t;
5
6
test_tohne_ptr;
7
test_t*mit_ptr_0;
8
test_t*mit_ptr=&ohne_ptr;
Ich muss ja die Struktur gezwungener Maßen zwei mal anlegen?!
Michael F. schrieb:> Im quellcode ja.>> Aber zu laufzeit, ist es wirklich nur eine struktur, auf die dann der> zeiger gesetzt wird.
Wird das bei der Speicherplatzberechnung mit einfließen die beiden
Structs?
Jan H. schrieb:> Ich muss ja die Struktur gezwungener Maßen zwei mal anlegen?!
Nein, du must sie nur einmal anlegen. Ein Zeiger auf deine Struktur ist
was völlig anderes. Du kannst das Wort Zeiger wortwörtlich nehmen. Der
Zeigt, wo deine Struktur liegt. Deswegen musst du ihn auch auf eine
angelegte Variable "einstellen" sprich zuweisen. Sonst zeigt der einfach
irgend wo hin und behauptet, das wäre deine struct.
Wenn du einen Zeiger an eine Funktion übergeben muss, legt man
üblicherweise nicht erst einen an, sondern benutzt den Adressoperator &.
Die Variante kennst du ja schon.
Okay.
Was mich jetzt noch Interessiert, braucht diese zweifache Anlegung auch
doppelten Speicher oder wird das nicht mit einberechnet?
Sprich der Compiler weiß, dass er dort nur hinzeigen soll?
Jan H. schrieb:> Okay.>> Was mich jetzt noch Interessiert, braucht diese zweifache Anlegung auch> doppelten Speicher oder wird das nicht mit einberechnet?
Welche zweifache Anlegung? Deine Struktur gibt es nur ein mal. Da
kannst du auch eine Million Zeiger drauf zeigen lassen, und doch ist die
Struktur nur einmal vorhanden. Natürlich brauchen die Zeiger selbst auch
Platz, aber eben nur den Platz für eine Adresse, nicht für die Daten
selbst.
> Sprich der Compiler weiß, dass er dort nur hinzeigen soll?
Stell dir mal vor, du fährst an einem Schild vorbei, das dir sagt, in
welche Richtung du zu einer Stadt fahren musst. Auch wenn um die Stadt
herum viele Schilder stehen, die in Richtung dieser Stadt zeigen, gibt
es die Stadt selbst dennoch nur einmal.
Rolf M. schrieb:> Jan H. schrieb:>> Okay.>>>> Was mich jetzt noch Interessiert, braucht diese zweifache Anlegung auch>> doppelten Speicher oder wird das nicht mit einberechnet?>> Welche zweifache Anlegung? Deine Struktur gibt es nur ein mal. Da> kannst du auch eine Million Zeiger drauf zeigen lassen, und doch ist die> Struktur nur einmal vorhanden. Natürlich brauchen die Zeiger selbst auch> Platz, aber eben nur den Platz für eine Adresse, nicht für die Daten> selbst.>>> Sprich der Compiler weiß, dass er dort nur hinzeigen soll?>> Stell dir mal vor, du fährst an einem Schild vorbei, das dir sagt, in> welche Richtung du zu einer Stadt fahren musst. Auch wenn um die Stadt> herum viele Schilder stehen, die in Richtung dieser Stadt zeigen, gibt> es die Stadt selbst dennoch nur einmal.
Wie groß ist dann der Zeiger?
Jan H. schrieb:> Wie groß ist dann der Zeiger?> test_t *mit_ptr = &ohne_ptr;
So groß, dass er die Adresse eines Objekts aufnehmen kann. Wieviel das
ist, hängt vom Prozessor und der Größe dessen Adressraums ab. Bei µCs
wird er meist 2 oder 4 Bytes groß sein.
Rolf M. schrieb:> Jan H. schrieb:>> Wie groß ist dann der Zeiger?>> test_t *mit_ptr = &ohne_ptr;>> So groß, dass er die Adresse eines Objekts aufnehmen kann. Wieviel das> ist, hängt vom Prozessor und der Größe dessen Adressraums ab. Bei µCs> wird er meist 2 oder 4 Bytes groß sein.
Ist er bei einem 8 Bit µC nicht nur ein Byte groß?
Peter II schrieb:> Jan H. schrieb:>> Ist er bei einem 8 Bit µC nicht nur ein Byte groß?>> nein, weil sonst könnte man nur 256 byte ram verwenden.
Okay.. Also ist die größte des Pointers abhängig von der Größe des RAM?
Jan H. schrieb:> Okay.. Also ist die größte des Pointers abhängig von der Größe des RAM?
Wie ich schon schrieb: Sie ist abhängig von der Größe des Adressraums.
Letztendlich bestimmt die Prozessor-Architektur das. Auf einem 64-Bit-PC
ist ein Zeiger z.B. 8 Bytes groß, unabhängig davon, ob da nun 1 GB RAM
oder 1 TB drin steckt.
Peter II schrieb:> Jan H. schrieb:>> Okay.. Also ist die größte des Pointers abhängig von der Größe des RAM?>> allgemein von den Möglichkeiten der Hardware.
Kannst du das mal bitte etwas genauer erklären..?
Hallo,
Jan H. schrieb:> Wie groß ist dann der Zeiger?test_t *mit_ptr = &ohne_ptr;
Wenn man keine ABI-Referenz zur Hand hat, dann tuts auch ein simples
sizeof():
1
intmain(){
2
printf("No Bytes of a pointer: %zu\n",sizeof(void*));
3
}
Dieser Test ergibt auf dem PC (Win 7, 64bit)
1
No Bytes of a pointer: 8
Also 64bit-Pointer
Auf einem AVR (gut, man würde kein printf() nehmen) ergibt es:
1
No Bytes of a pointer: 2
Also 16bit-Pointer
Jan H. schrieb:> Peter II schrieb:>> Jan H. schrieb:>>> Ist er bei einem 8 Bit µC nicht nur ein Byte groß?>>>> nein, weil sonst könnte man nur 256 byte ram verwenden.>> Okay.. Also ist die größte des Pointers abhängig von der Größe des RAM?
Nein, andersherum wird ein Schuh draus.
Die Größe der Pointer gibt den maximal adressierbaren Speicher an.
Diese Größe muss dann sinnvoll gewählt werden.
Mit freundlich Grüßen,
N.G.
Jan H. schrieb:> Warum zeigt er mir jetzt 1 Byte für einen> char an?> char *ptr = NULL;>> int main(void){> printf("Size of Pointer %d\n\r",sizeof(*ptr));> }
Weil du den Pointer de-referenzierst. Damit bekommst du die Größe vom
Typ, auf den der Pointer zeigt (hier char).
Also lass das Sternchen vor ptr im sizeof weg
Mit freundlichen Grüßen,
N.G.
N. G. schrieb:> Jan H. schrieb:>> Warum zeigt er mir jetzt 1 Byte für einen>> char an?>> char *ptr = NULL;>>>> int main(void){>> printf("Size of Pointer %d\n\r",sizeof(*ptr));>> }>> Weil du den Pointer de-referenzierst. Damit bekommst du die Größe vom> Typ, auf den der Pointer zeigt (hier char).> Also lass das Sternchen vor ptr im sizeof weg>> Mit freundlichen Grüßen,> N.G.
Okay. Wieso ist der Zeiger aber größer als der Eigentliche
Speicherbereich?
Ein char benötigt 1 Byte, das heißt ein Zeiger vom Typ char, müsste er
nicht auch nur 1 Byte groß sein? Das würde doch ausreichen um die
Adresse aufzunehmen?
Jan H. schrieb:> Wieso ist der Zeiger aber größer als der Eigentliche Speicherbereich?> Ein char benötigt 1 Byte, das heißt ein Zeiger vom Typ char, müsste er> nicht auch nur 1 Byte groß sein? Das würde doch ausreichen um die> Adresse aufzunehmen?
Überleg' mal. Wenn ein Pointer so groß wäre wie das Objekt, auf das er
zeigt, würde das die Anzahl damit verwaltbarer Objekte beeinflussen.
Bei Deinem 1-Byte-Beispiel könntest Du also nur 256 chars damit
verwalten.
Na? Klingelt's?
Jan H. schrieb:> Okay. Wieso ist der Zeiger aber größer als der Eigentliche> Speicherbereich?> Ein char benötigt 1 Byte, das heißt ein Zeiger vom Typ char, müsste er> nicht auch nur 1 Byte groß sein? Das würde doch ausreichen um die> Adresse aufzunehmen?
Du musst dich von der Vorstellung verabschieden, dass die Größe eines
Zeigers irgendwas mit der Größe des Objekts zu tun hat, auf das er
zeigt.
In einem Zeiger steht eine Adresse, d.h. er ist so groß wie eine
Adresse. Ob an dieser Adresse nun ein Byte steht oder eine 10 kB große
komplexe Struktur, hat keinen Einfluss darauf, wie groß die Adresse
selber ist.
Oder stell es dir, wie eine langes straße vor und dein pointer soll auf
das jeweilige haus zeigen. Ob das haus groß , oder klein ist , spielt
keine rolle.
Dasselbe macht der zeiger auch, er gibt an, an welcher speicherstelle
das gesuchte liegt.
Hast du eine CPU mit linearen speicher, dann muß er eben so groß sein,
daß er wiklich auf alle zellen zeigen kann.
Ist es eine segmentierte CPU, dann ist er so froß, wie das segment ist.
Aber hier bei den Atmels, sind es einfach lineare adressen.