Forum: Mikrocontroller und Digitale Elektronik Pointer auf Struct - Unterschiede


von Jan H. (janiiix3)


Lesenswert?

Moin Moin..

Wo ist eigentlich der Unterschied? Kann es zur Laufzeit Fehler geben?
1
typedef struct test{
2
  Uint8_t var;
3
}test_t;
4
5
test_t *mit_ptr;
6
test_t ohne_ptr;
7
8
void read(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?

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

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.

von Jan H. (janiiix3)


Lesenswert?

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?

von nicht"Gast" (Gast)


Lesenswert?

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.

von nicht"Gast" (Gast)


Lesenswert?

Meh, vergiss meinen Post, ich brauch Kaffee

von nicht"Gast" (Gast)


Lesenswert?

Jan H. schrieb:
> Wie würde das Aussehen?


test_t ohne_ptr;
test_t *mit_ptr = &ohne_ptr;

von Kaj (Gast)


Lesenswert?

Jan H. schrieb:
> Wie würde das Aussehen?
1
test_t ohne_ptr;
2
test_t *mit_ptr = &ohne_ptr;
3
4
test_t *new_ptr = new test_t;  //  C++
5
test_t *malloc_ptr1 = (test_t *)malloc(sizeof(test_t));  //  C/C++
6
test_t *malloc_ptr2 = malloc(sizeof(test_t));  //  C

von Jan H. (janiiix3)


Lesenswert?

Kaj schrieb:
> Jan H. schrieb:
>> Wie würde das Aussehen?
>
1
> test_t ohne_ptr;
2
> test_t *mit_ptr = &ohne_ptr;
3
> 
4
> test_t *new_ptr = new test_t;  //  C++
5
> test_t *malloc_ptr1 = (test_t *)malloc(sizeof(test_t));  //  C/C++
6
> test_t *malloc_ptr2 = malloc(sizeof(test_t));  //  C
7
>

Ich kann es aber ohne Fehler Kompilieren. Was passiert denn wenn ich es 
einfach nur so übergebe?
1
typedef struct test{
2
  Uint8_t var;
3
}test_t;
4
5
test_t *mit_ptr;
6
7
8
read(mit_ptr){
9
}

Was passiert wenn ich es so übergebe? Er muss ja irgendwas falsch machen 
dann..

von Phantomix X. (phantomix)


Lesenswert?

"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).

von Rolf M. (rmagnus)


Lesenswert?

Jan H. schrieb:
1
typedef struct test{
2
  Uint8_t var;
3
}test_t;
4
5
test_t *mit_ptr;
6
7
8
read(mit_ptr){
9
}
>
> 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. ;-)

von Jan H. (janiiix3)


Lesenswert?

Rolf M. schrieb:
> Jan H. schrieb:
>
1
> typedef struct test{
2
>   Uint8_t var;
3
> }test_t;
4
> 
5
> test_t *mit_ptr;
6
> 
7
> 
8
> read(mit_ptr){
9
> }
10
>
>>
>> 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
typedef struct{
2
  
3
  int var;
4
}test_t;
5
6
test_t ohne_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?!

von Michael F. (sharpals)


Lesenswert?

Im quellcode ja.

Aber zu laufzeit, ist es wirklich nur eine struktur, auf die dann der 
zeiger gesetzt wird.

von Jan H. (janiiix3)


Lesenswert?

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?

von nicht"Gast" (Gast)


Lesenswert?

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.

von Jan H. (janiiix3)


Lesenswert?

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?

von Rolf M. (rmagnus)


Lesenswert?

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.

: Bearbeitet durch User
von Jan H. (janiiix3)


Lesenswert?

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?
1
test_t *mit_ptr = &ohne_ptr;

von Rolf M. (rmagnus)


Lesenswert?

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.

von Jan H. (janiiix3)


Lesenswert?

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ß?

von Peter II (Gast)


Lesenswert?

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.

von Jan H. (janiiix3)


Lesenswert?

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?

von Peter II (Gast)


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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.

von Jan H. (janiiix3)


Lesenswert?

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..?

von N. G. (newgeneration) Benutzerseite


Lesenswert?

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
int main() {
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.

von Jan H. (janiiix3)


Lesenswert?

Warum zeigt er mir jetzt 1 Byte für einen char an?
1
char *ptr = NULL;
2
3
int main(void){  
4
  printf("Size of Pointer %d\n\r",sizeof(*ptr));
5
}

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

Jan H. schrieb:
> Warum zeigt er mir jetzt 1 Byte für einen

weil der * zu viel ist

von N. G. (newgeneration) Benutzerseite


Lesenswert?

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.

von Jan H. (janiiix3)


Lesenswert?

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?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

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?

: Bearbeitet durch User
von Kaj (Gast)


Lesenswert?

Jan H. schrieb:
> Das würde doch ausreichen um die
> Adresse aufzunehmen?
Wie willst du mit einem Byte 4GB (2^32 - 1 Byte) RAM adressieren?

von Rolf M. (rmagnus)


Lesenswert?

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.

von Michael F. (sharpals)


Lesenswert?

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.

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.