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?
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.
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".
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_tBuff=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.
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]
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.
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.
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.
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.
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.
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.
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.
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.
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.
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!
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.