Forum: Mikrocontroller und Digitale Elektronik Pointer in Funktion..


von Thomas S. (Gast)


Lesenswert?

Moin Moin..

Wie ist das eigentlich, wenn ich einer Funktion die einen Pointer 
erwartet die Adresse einer Variablen übergebe.. Und diese Funktion 
mehrere Bytes ab Anfang dieser Adresse schreiben soll? Wie kann ich 
diese Bytes abrufen? Also die erste Stelle ist klar.. Geht das 
überhaupt?
1
uint8_t Buff=0;
2
3
uint8_t twi_reads(TWI_t *twi, uint8_t reg, uint8_t numb, uint8_t *buff){
4
   
5
  uint8_t BytesReaded=0;
6
   
7
   twi->MASTER.ADDR = ((SLAVE_ADDRESS<<1));
8
   while(!(twi->MASTER.STATUS&TWI_MASTER_WIF_bm));
9
   
10
   twi->MASTER.DATA = reg;
11
   while(!(twi->MASTER.STATUS&TWI_MASTER_WIF_bm));
12
   
13
   twi->MASTER.ADDR = ((SLAVE_ADDRESS<<1)|0x01);
14
     
15
  for (uint8_t ReadCnt=0;ReadCnt<numb;ReadCnt++){  
16
    
17
    twi->MASTER.CTRLC = TWI_MASTER_CMD_RECVTRANS_gc;
18
    while(!(twi->MASTER.STATUS & TWI_MASTER_RIF_bm));
19
    *buff++ = twi->MASTER.DATA;  
20
   }
21
22
   twi->MASTER.CTRLC = TWI_MASTER_ACKACT_bm | TWI_MASTER_CMD_STOP_gc;
23
24
   return BytesReaded;
25
}

Wenn ich die Funktion jetzt aufrufe..
1
twi_reads(&twi,0x00,10,&Buff);

An das erste Byte komme ich, wie bekomme ich die anderen 9 Bytes? Oder 
muss es ein Array sein?!

von kurz um (Gast)


Lesenswert?

Entweder
But[0] ...
But[8] ...
Oder
But++ ...

von Thomas S. (Gast)


Lesenswert?

kurz um schrieb:
> Entweder
> But[0] ...
> But[8] ...
> Oder
> But++ ...

Also geht es nur mit einem Array?

von Irgendwer (Gast)


Lesenswert?

Thomas S. schrieb:
>
> uint8_t Buff=0;
>
> An das erste Byte komme ich, wie bekomme ich die anderen 9 Bytes?

Strenggenommen garnicht weil du nur Speicher für ein Byte reserviert 
hast und somit kannst du auch nur dieses eine beschreiben/lesen.

von Sven B. (scummos)


Lesenswert?

Irgendwer schrieb:
> Thomas S. schrieb:
>>
>> uint8_t Buff=0;
>>
>> An das erste Byte komme ich, wie bekomme ich die anderen 9 Bytes?
>
> Strenggenommen garnicht weil du nur Speicher für ein Byte reserviert
> hast und somit kannst du auch nur dieses eine beschreiben/lesen.

Streng genommen ist gut, dass das nicht sofort hard faulted ist ein 
Wunder ;p

Du musst mehr Speicher reservieren, entweder uint8_t Buf[8]; oder so, 
oder mit malloc (wenn deine Plattform das hat). Zugriff geht dann mit [] 
oder Pointerarithmetik.

Das Perfekt von "read" ist "read", nicht "readed".

von Axel S. (a-za-z0-9)


Lesenswert?

Thomas S. schrieb:

> Wie ist das eigentlich, wenn ich einer Funktion die einen Pointer
> erwartet die Adresse einer Variablen übergebe..

Ein Pointer ist am Ende eine Adresse. Wobei "Adresse" im Kontext von C 
streng genommen falsch ist, denn C kennt das Konzept "Adresse" nicht. 
Das Konzept heißt "Pointer". Der "&" Operator den du unten verwendest, 
liefert einen Pointer auf das Objekt, auf das er angewendet wird. Daß 
dieser Operator manchmal als "Adress-Operator" bezeichnet wird, ist ein 
sprachliches Mißgeschick.

> Und diese Funktion
> mehrere Bytes ab Anfang dieser Adresse schreiben soll?

Eine Variable kann ein oder mehrere Bytes belegen. Wenn du versuchst, 
mehr Bytes über den Pointer zu schreiben, als die Variable tatsächlich 
belegt, dann schreibst du am Ende in "fremden" Speicher. Bspw. in eine 
andere Variable, die der Compiler im Speicher hinter deiner Variable 
abgelegt hat. Das ist ein grober Programmierfehler und führt zu schwer 
zu findenden Fehlern. Eine ganze Klasse von Sicherheitslücken in 
Software beruht auf so etwas.

>
1
> uint8_t Buff=0;

Also eine Variable, die genau 1 Byte lang ist.

> Wenn ich die Funktion jetzt aufrufe..
>
1
> twi_reads(&twi,0x00,10,&Buff);

Dann schreibt die Funktion 10 Bytes in den Speicher. Das erste davon 
landet in der Variable Buff, die anderen 9 entweder in anderen 
Variablen oder bestenfalls in nichtbelegtem Speicher.

> muss es ein Array sein?!

Genau so. Es muß eine Datenstruktur sein, die mindestens 10 Bytes halten 
kann. Und wenn du die 10 Bytes einzeln lesen können willst, dann muß die 
Datenstruktur einen byteweisen Zugriff mit C-Mitteln erlauben. Ein Array 
von uint8_t mit (mindestens) Länge 10 wäre die kanonische Wahl.

von Mikro 7. (mikro77)


Lesenswert?

Axel S. schrieb:
> Wobei "Adresse" im Kontext von C
> streng genommen falsch ist, denn C kennt das Konzept "Adresse" nicht.

The unary & operator yields the address of its operand. [§6.5.3.2]

von Axel S. (a-za-z0-9)


Lesenswert?

Mikro 7. schrieb:
> Axel S. schrieb:
>> Wobei "Adresse" im Kontext von C
>> streng genommen falsch ist, denn C kennt das Konzept "Adresse" nicht.
>
> The unary & operator yields the address of its operand. [§6.5.3.2]

[Mod: Beleidigung gelöscht]

Wenn du schon den Standard zur Hand hast: schlag doch mal die Definition 
des Konzepts "Pointer" nach. Und dann zeig mir, wo der Standard das 
Konzept "Adresse" in ähnlicher Form behandelt. Ach, tut er nicht?

Ich sage es gern noch einmal: technisch ist ein Pointer im wesentlichen 
eine Adresse. Konzeptionell ist er aber noch mehr: außer der Adresse 
enthält ein Pointer auch Informationen über den Typ des referenzierten 
Objekts (und damit auch über dessen Größe im Speicher). Erst dadurch ist 
Pointer-Arithmetik überhaupt erst sinnvoll machbar. Und der Compiler 
kann potentiell falschen Code wie etwa die implizite Umwandlung von 
Pointern auf verschiedene Typen überhaupt erst erkennen.

: Bearbeitet durch Moderator
von W.S. (Gast)


Lesenswert?

Axel S. schrieb:
> Konzeptionell ist er aber noch mehr: außer der Adresse
> enthält ein Pointer auch Informationen über den Typ des referenzierten
> Objekts

Nein, das tut er nicht. Der Zeiger als solcher ist nix anderes als eben 
eine Zahl, die auf eine Adresse im zugehörigen Adreßraum zeigt. Mehr 
nicht.

Was du meinst, ist etwas anderes, nämlich die Kenntnis des Compilers 
darüber, für welchen Datentyp und ggf. welchen Adreßraum dieser Zeiger 
gedacht ist. Das ist der eigentliche Knackpunkt.

Anstatt zu räsonieren, wie man einen "Pointer in Funktion" denn dazu 
benutzen kann, auf irgend etwas zuzugreifen, worauf dieser Pointer denn 
grad zeigt, sollte man all solche Pointerakrobatik generell vermeiden 
und stattdessen eben als Argument der Funktion einen Zeiger passenden 
Typs verwenden, z.B. eben einen Zeiger auf ein struct oder ein Array. 
Dann ergibt sich der richtige Zugriff von selbst und ohne jedes Casten 
und man hat eine mögliche Fehlerquelle weniger.

W.S.

von Kurz um (Gast)


Lesenswert?

Und da wir das jetzt geklärt hätten und die Interpretation zum Zeitpunkt 
der Übersetzung und zur Laufzeit kennen, bitte wieder zurück zum Thema.

In der Funktion habe ich keine Kenntnis über die tatsächliche Größe der 
Datenstruktur. Ich muss mich auf den Aufrufer verlassen.
Und der Zugriff erfolgt klassisch über den Index oder mit 
Zeigerarithmetik.

von Mikro 7. (mikro77)


Lesenswert?

Eine Adresse ist eine Konstante. [rvalue]

Ein Pointer ist eine Variable. [lvalue]

Wie jede andere Variable hat ein Pointer eine Adresse (&-operator) und 
eine Größe (sizeof-operator).

Axel S. schrieb:
> Wenn du schon den Standard zur Hand hast: schlag doch mal die Definition
> des Konzepts "Pointer" nach. Und dann zeig mir, wo der Standard das
> Konzept "Adresse" in ähnlicher Form behandelt. Ach, tut er nicht?

Wenn du Argumente hast, dann bringe sie. Laß nicht andere für dich 
suchen.

von Rolf M. (rmagnus)


Lesenswert?

Mikro 7. schrieb:
> Eine Adresse ist eine Konstante. [rvalue]

Genauer gesagt ist eine Adresse ein Wert (ISO C: "value").

> Ein Pointer ist eine Variable. [lvalue]

Um sich auch hier an ISO C zu orientieren: Ein Pointer ist ein Objekt. 
Eine Variable ist ein Objekt, das einen Namen hat.

> Wie jede andere Variable hat ein Pointer eine Adresse (&-operator) und
> eine Größe (sizeof-operator).

Und wie jede andere Variable hat ein Pointer einen Wert. Im Falle eines 
Pointers ist dieser Wert eine Adresse.

: Bearbeitet durch User
von Axel S. (a-za-z0-9)


Lesenswert?

Mikro 7. schrieb:
> Eine Adresse ist eine Konstante. [rvalue]
> Ein Pointer ist eine Variable. [lvalue]

Nein. C kennt nicht so etwas wie "Adresse", sondern nur Pointer. Und ein 
Pointer ist immer eine Variable, "Pointer" ist der Typ (ein Teil des 
Typs) dieser Variable.

> Wie jede andere Variable hat ein Pointer eine Adresse (&-operator) und
> eine Größe (sizeof-operator).

Korrekt, aber irrelevant.

> Axel S. schrieb:
>> Wenn du schon den Standard zur Hand hast: schlag doch mal die Definition
>> des Konzepts "Pointer" nach. Und dann zeig mir, wo der Standard das
>> Konzept "Adresse" in ähnlicher Form behandelt. Ach, tut er nicht?
>
> Wenn du Argumente hast, dann bringe sie. Laß nicht andere für dich
> suchen.

Ich habe mein Argument vorgebracht. Dein Gegenargument, daß das Wort 
"Adresse" in Text des Standards vorkommt, ist keins. Denn ich habe nicht 
gesagt, daß es das Wort nicht gibt, sondern daß es das Konzept nicht 
gibt. Und zwar deswegen, weil C ein erweitertes Konzept hat. Und das 
heißt nun mal Pointer. Gerade bei der Diskussion mit Anfängern (wie es 
der TE offensichtlich ist) ist es wichtig, korrekte und konsistente 
Begriffe zu verwenden. Die Verwendung von "Adresse" als Synonym für 
"Pointer" ist das nicht.

Es gibt noch mehr Argumente dafür, daß Pointer keine Adressen sind. Oder 
doch zumindest nicht nur Adressen. Zum einen, wie bereits gesagt, 
enthält der Pointer immer auch Information über das Objekt, auf das er 
zeigt. Zum zweiten enthält er auch Informationen darüber, in welchem 
Adressraum sich das Objekt befindet (vorausgesetzt die Zielarchitektur 
hat mehrere).

Für Pointer auf Daten hat avr-gcc zwar spät, aber dankenswerter Weise 
endlich doch, Pointer auf Konstanten im Flash eingeführt. Die sehen auf 
C-Seite nicht anders aus, verhalten sich aber bei der Codegenerierung 
ganz anders. Für Funktionspointer galt das auch bei avr-gcc immer schon 
(die liegen immer im Flash). Einer Adresse als nackter Zahl kann man 
nicht ansehen, auf welchen Adressraum sie sich bezieht. Ein Pointer 
"weiß" das.

Weiterhin kann der Compiler Variablen auch ganz in Registern halten. Und 
auch auf solche Variablen kann man Pointer anlegen. Und das obwohl so 
eine Variable keine Adresse im herkömmlichen Sinn hat. NB: vermutlich 
macht avr-gcc das nicht, sondern zwingt eine solche Variable ins RAM. 
Weil es einfacher ist, immer den gleichen Code bei der Dereferenzierung 
von Pointern zu generieren. Aber im Prinzip spricht nichts dagegen, auch 
per Pointer referenzierte Variablen in Registern zu halten.

von Rolf M. (rmagnus)


Lesenswert?

Axel S. schrieb:
> Die Verwendung von "Adresse" als Synonym für "Pointer" ist das nicht.

Du bist eigentlich der einzige, der hier behauptet, das sei das gleiche.

> Es gibt noch mehr Argumente dafür, daß Pointer keine Adressen sind.

Ich zitiere mal:

Axel S. schrieb:
> Ein Pointer ist am Ende eine Adresse.

Axel S. schrieb:
> Ich sage es gern noch einmal: technisch ist ein Pointer im wesentlichen
> eine Adresse.

Jetzt sagst du das Gegenteil. Entscheide dich doch mal.

> Weiterhin kann der Compiler Variablen auch ganz in Registern halten. Und
> auch auf solche Variablen kann man Pointer anlegen. Und das obwohl so
> eine Variable keine Adresse im herkömmlichen Sinn hat.

Das sind aber alles Optimierungen, die hinter den Kulissen ablaufen und 
damit nicht relevant sind. ISO C definiert eine abstrakte Maschine, auf 
der der Code exakt so ausgeführt wird, wie es in der Norm definiert ist.
(Zitat: "The semantic descriptions in this International Standard 
describe the behavior of an abstract machine in which issues of 
optimization are irrelevant." und "In the abstract machine, all 
expressions are evaluated as specified by the semantics.")

Rein auf Ebene von ISO C steht in dem Zeiger eine Adresse drin, und die 
kann man übrigens auch ganz real da rauslesen und sich anzeigen lassen.
Ob der Optimizer sich entscheidet, die indirekte Adressierung oder gar 
die ganze Speicherstelle wegzuoptimieren, hat damit nichts zu tun.
Zu deinem Register-Beispiel: In ISO C gibt es keine Register und damit 
auch keine Pointer auf Register. Es gibt Pointer auf Objekte, und jedes 
Objekt hat eine Adresse (siehe Zitat unten).

Axel S. schrieb:
> C kennt nicht so etwas wie "Adresse", sondern nur Pointer.

Hier mal nur ein paar wenige weitere Zitate zu Adressen:
"byte
addressable unit of data storage large enough to hold any member of 
the basic character set of the execution environment
NOTE 1 It is possible to express the address of each individual byte 
of an object uniquely."

"An object exists, has a constant address "

"The unary & operator returns the address of its operand."

"An address constant is a null pointer, a pointer to an lvalue 
designating an object of static storage duration, or a pointer to a 
function designator"

Klingt das für dich echt, als gäbe es kein Konzept von Adressen?

Axel S. schrieb:
> Es gibt noch mehr Argumente dafür, daß Pointer keine Adressen sind. Oder
> doch zumindest nicht nur Adressen. Zum einen, wie bereits gesagt,
> enthält der Pointer immer auch Information über das Objekt, auf das er
> zeigt. Zum zweiten enthält er auch Informationen darüber, in welchem
> Adressraum sich das Objekt befindet (vorausgesetzt die Zielarchitektur
> hat mehrere).

Da vermischst du wieder die von C definierte abstrakte Maschine (also 
das, was C "kennt") mit der Hardware, auf der nachher das Programm 
läuft. Auf C-Ebene ist es einfach nur eine Adresse, auch wenn auf Ebene 
der Hardware noch mehr dahinter stecken mag. Sowas gibt es an vielen 
Stellen in C, wie z.B. bei Flags, die es in der Hardware geben mag und 
die dort auch benötigt werden, die es aber auf der abstrakten C-Maschine 
nicht gibt.

: Bearbeitet durch User
von W.S. (Gast)


Lesenswert?

Kurz um schrieb:
> In der Funktion habe ich keine Kenntnis über die tatsächliche Größe der
> Datenstruktur. Ich muss mich auf den Aufrufer verlassen.
> Und der Zugriff erfolgt klassisch über den Index oder mit
> Zeigerarithmetik.

Das ist Mumpitz. In der Funktion hat man sehr wohl die Kenntnis über 
das, was man da als Argument erwartet - und genau DARUM geht es hier. 
Der Aufrufer hat sich daran zu halten, der Funktion ein Argument zu 
liefern, was diese erwartet. So herum.

W.S.

von Schlaubie Schlumpf (Gast)


Lesenswert?

const int a_const = 42;
eine Variable, deren Wert und dessen Speicheradresse sich im 
Programmverlauf nicht ändert.

int a_var = 42;
eine Variable, dessen Wert sich im Programmverlauf ändern kann und 
dessen Speicheradresse sich im Programmverlauf nicht ändert.

int *a_ptr;
ein Zeiger, dessen Wert und Speicheradresse sich im Programmverlauf 
ändern kann.

Beispiel :

a_var = a_const; // alles OK

a_const  = a_var; // Fehler, a_const kann sich nicht ändern

*a_ptr = a_var; // Wert von a_var wird von a_ptr  übernommen, Adresse 
von a_ptr ändert sich nicht.

a_ptr = &a_var; // Wert und Adresse ändert sich von a_ptr (übernimmt 
Werte von a_var)

a_var = a_ptr; // Fehler, a_var bekommt nicht die Adresse von a_ptr als 
Wert zugewiesen, da int vorzeichenbehaftet ist. a_var müsste als 
unsigned int deklariert sein, wenn das funktionieren soll.

Mit Variablen und Zeigern kann man viel falsch machen, das aber 
syntaktisch richtig ist. Nur war die eigene Zielsetzung eine andere.

von kurz um (Gast)


Lesenswert?

W.S. schrieb:
> Kurz um schrieb:
> In der Funktion habe ich keine Kenntnis über die tatsächliche Größe der
> Datenstruktur. Ich muss mich auf den Aufrufer verlassen.
> Und der Zugriff erfolgt klassisch über den Index oder mit
> Zeigerarithmetik.
>
> Das ist Mumpitz. In der Funktion hat man sehr wohl die Kenntnis über
> das, was man da als Argument erwartet - und genau DARUM geht es hier.
> Der Aufrufer hat sich daran zu halten, der Funktion ein Argument zu
> liefern, was diese erwartet. So herum.
>
> W.S.

Bist du nicht der deutschen Sprache mächtig???
Ich schrieb doch, dass die Verantwortung beim Aufrufer liegt!!!

In der Funktion sehe ich nur, die in der Parameterliste deklarierte, 
Variable Pointer auf uint8_t. In der Funktion sehe ich aber nicht, 
wieviel Speicher dahinter steckt.

Bitte Aufwachen, guten Morgen!

von kurz um (Gast)


Lesenswert?

Wieviel Speicher dahinter steckt, worauf der Pointer zeigt.

Für die Erbsenzähler, was es hier welche gibt. ;-)

von Georg G. (df2au)


Lesenswert?

Schlaubie Schlumpf schrieb:
> Mit Variablen und Zeigern kann man viel falsch machen

Das hast du eindrucksvoll bewiesen. Deine Aussagen mit a_ptr sind - 
vorsichtig ausgedrückt - nicht ganz richtig.

Beispiele:
> *a_ptr = a_var; // Wert von a_var wird von a_ptr  übernommen, Adresse
> von a_ptr ändert sich nicht.

Der Wert von a_var wird an die Speicherstelle kopiert, auf die a_ptr 
zeigt. Die Adresse von a_ptr ändert sich nie, nur die Adresse, auf die 
a_ptr zeigt.

> a_ptr = &a_var; // Wert und Adresse ändert sich von a_ptr (übernimmt
> Werte von a_var)
a_ptr zeigt auf die Adresse von a_var, er hat den Wert dieser Adresse, 
aber seine Adresse bleibt gleich.

von Zeiger auf ... (Gast)


Lesenswert?

ein Bild sagt mehr als 1000 Worte
http://darksiren.net/stuff/PointersInC.gif

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.