Forum: Compiler & IDEs *Pointer und struct, Anfängerfrage


von Simon (Gast)


Lesenswert?

SYNOPSIS
1
int modbus_write_and_read_registers
2
(modbus_t *ctx, int write_addr, int write_nb, const uint16_t *src, int read_addr, int read_nb, const uint16_t *dest);

"You must take care to allocate enough memory to store the results in 
dest (at least nb * sizeof(uint16_t))."


const uint16_t *dest

1) Wieso wird hier const verwendet?
2) uint16_t *dest

bedeutet das jedesmal wen ich ein dest++ mache er den Pointer um 16 bits 
bewegt?

von adf (Gast)


Lesenswert?

Simon schrieb:
> bedeutet das jedesmal wen ich ein dest++ mache er den Pointer um 16 bits
> bewegt?

??? dest++ inkrementiert den Pointer, da wird gar nicht bewegt.

von Simon (Gast)


Lesenswert?

adf schrieb:
> ??? dest++ inkrementiert den Pointer, da wird gar nicht bewegt.

um 16 Bit?

Was wäre anders wenn es so heiszen würde:
const uint8_t *dest)

von Oliver (Gast)


Lesenswert?


von Simon (Gast)


Lesenswert?

Danke, bin noch am lesen, garnicht schlecht.

von Simon (Gast)


Lesenswert?

Ich checks immer noch nicht, warum const?

const sagt aus das die Variable einmal deklariert und zugewiesen wird, 
danach nicht mehr geändert.

Bedeutet das nun das ich die Variable innerhalb der funktion nicht vor 
habe zu verändern?
1
void funktion (const uint16_t *dest);

der Aufruf wäre dann mit
1
funktion(*variable); ?

Und was sagt mir uint16_t in dem Zusammenhang? das der Pointer aus einer 
16 Bit addresse besteht?

von DirkB (Gast)


Lesenswert?

Simon schrieb:
> der Aufruf wäre dann mitfunktion(*variable); ?
Nein

mitfunktion(&variable);

Die Funktion erwartet eine Adresse und die bekommst du mit dem 
Adressoperator &

> Und was sagt mir uint16_t in dem Zusammenhang?
Das an der Adresse auf die der Zeiger zeigt eine vorzeichenlose 16-Bit 
Ganzzahl steht.

Der Compiler muss wissen wie er die Daten an der Adresse interpretieren 
soll.

von Karl H. (kbuchegg)


Lesenswert?

Simon schrieb:
> Ich checks immer noch nicht, warum const?

Gute Frage

> const sagt aus das die Variable einmal deklariert und zugewiesen wird,
> danach nicht mehr geändert.

An dieser Stelle sagt das const aus, dass die aufgerufene Funktion den 
Pointer nicht benutzen wird um über diesen Pointer die Werte an der 
Stelle im Speicher zu verändern, auf die der Pointer zeigt.

Beispiel

void foo( uint16_t * pDest )
{
  *pDest = 5;
}

int main()
{
  uint16_t i;

  foo( &i );
}

ich übergebe der Funktion die Adresse von i. Die Funktion benutzt diese 
Adresse, um über diese Adresse die Variable i zu verändern.

Und jetzt das ganze const

void foo( const uint16_t * pDest )
{
  *pDest = 5;
}

int main()
{
  uint16_t i;

  foo( &i );
}

jetzt gibt mir die Funktion die Zusicherung, genau das nicht zu tun. Sie 
wird die Adresse, die ich ihr gebe, nicht dazu benutzen um die Variable 
zu verändern.
Wenn du das compilierst, dann wird es einen Fehler hier
  *pDest = 5;
geben. Denn diese Operation versucht genau das, was durch das const in 
der Argumentliste ausgeschlossen wurde. Der Compiler verhindert das 
daher.

Allerdings:
Ich weiß zwar nicht, was deine Funktion genau macht. Aber wenn ich raten 
müsste, würde ich den Argumentnamen 'dest' alsw Kurzform für Destination 
ansehen, also das Ziel einer Operation. Und da würde ich mal raten, dass 
dieses Ziel irgendwie verändert wird. Wodurch das const keinen Sinn 
ergibt.
Aber: Das ist jetzt nur geraten. Genaueres kann man nur sagen, wenn man 
weiß was das für eine Funktion ist und welchen Zweck sie hat.

von Oliver (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Und da würde ich mal raten, dass
> dieses Ziel irgendwie verändert wird. Wodurch das const keinen Sinn
> ergibt.

Da brauchst du nicht zu raten, das steht sogar da:

Simon schrieb:
> "You must take care to allocate enough memory to store the results in
> dest (at least nb * sizeof(uint16_t))."

Da hat der unbekannte Autor der Funktion das mit dem const auch nicht 
auf die Reihe gekriegt. Im Sourcecode wurde die aber wohl nicht 
ausgeliefert, denn jeder "anständige" C-Compipler würde sich weigern, 
den Schreibzugriff in das Feld zu übersetzen.

Oliver

von Decius (Gast)


Lesenswert?

Egal ob du eine Variable als uint16_t oder uint8_t vereinbarst, haben 
Pointer eine konstante Größe. Sie beinhalten doch nur die Adresse auf 
eine Speicherstelle. Der Datentyp definiert nur wie die Daten an dieser 
Speicherstelle zu interpretieren sind.

Wie ein Pointer auf dekrementieren oder inkrementieren reagiert kann 
ohne Bezug zu einem realen System nicht definiert werden. Auf der Intel 
Plattform ist eine Byteweise Addressierung üblich. Das heißt, ++ und -- 
verändern die Pointeradresse um ein Byte, egal um welchen Datentyp es 
sich handelt.

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

Decius schrieb:
> Das heißt, ++ und --
> verändern die Pointeradresse um ein Byte, egal um welchen Datentyp es
> sich handelt.

Nein. Da heißt es aufpassen.

von Decius (Gast)


Lesenswert?

habe ja geschrieben, das das Systemabhängig ist.

von Decius (Gast)


Lesenswert?

Ok, hinsichtlich ++ und -- bin ich jertzt doch etwas unsicher. :-)

Hsabe auch sowas gelesen, daß das Ergebnis in diesen Fällen doch vom 
Datentyp abhängig ist. Also wenn du ein Array von short hast, verändert 
die Adresse sich um 2Byte.

Aber Systemabhängig muß das ganze aber auch sein. Denn die Byteweiyse 
Addressierung der intelplattform ist bei ARM's nicht üblich.

von Oliver (Gast)


Lesenswert?

Decius schrieb:
> Wie ein Pointer auf dekrementieren oder inkrementieren reagiert kann
> ohne Bezug zu einem realen System nicht definiert werden.

Natürlich kann das vollständig definiert werden, und das ist es auch. 
Kurz gesagt, zeigt der pointer nach der Inkremetierung auf das folgende 
Element gleichen Typs. So einfach ist das. Wie die Bytes im Speicher 
angeordnet sind, ist zwar implementationsabhängig, abder der Spache C 
völlig egal.

Oliver

von Decius (Gast)


Lesenswert?

ok, hast recht. Ist wieder gerade gerückt. :-)

von Dosmo (Gast)


Lesenswert?

Simon schrieb:
> Ich checks immer noch nicht, warum const?
>
> const sagt aus das die Variable einmal deklariert und zugewiesen wird,
> danach nicht mehr geändert.
>
>
> Bedeutet das nun das ich die Variable innerhalb der funktion nicht vor
> habe zu verändern?
1
const int a;
 ist eine Konstante.
1
const int *a;
 ist ein (variabler) Zeiger auf eine Konstante.
Der Zeiger selber ist dann keine Konstante!

Stell Dir vor, Du hast eine Tabelle aus Konstanten und Du willst mit 
einem Zeiger durch diese Tabelle gehen. Dann muß der Zeiger veränderbar 
sein, neech?
1
int * const a;
 wäre ein konstanter Zeiger auf eine Variable.
1
const int * const a;
 wäre ein konstanter Zeiger auf eine Konstante.

Es gibt tatsächlich Anwendungsfälle für alle Varianten.

von Klaus W. (mfgkw)


Lesenswert?

Dosmo schrieb:
> const int a; ist eine Konstante.const int *a; ist ein (variabler) Zeiger auf 
eine Konstante.

Jein.
Genau genommen ist es eine Variable und mit dem const sagt man, daß man 
im Geltungsbereich dieser Deklaration diese Variable nicht ändern 
möchte.

Der Unterschied ist z.B. dann relevant, wenn man Parameterdeklarationen 
hat:
1
void f1( int * p_i )
2
{
3
   *p_i++;
4
   // ...
5
}
6
7
void f2( const int * p_i )
8
{
9
   // jetzt nicht mehr möglich: *p_i++;
10
   // ...
11
}
12
13
...
14
   int          i = 0;
15
   const int    ci = 0;
16
   f1( &i );  // ok
17
   f1( &ci ); // falsch, da f1() nicht verspricht, ci nicht zu ändern
18
   f2( &i );  // ok, auch wenn i nicht const ist
19
   f2( &ci ); // ok, da f2() verspricht, ci nicht zu ändern

Beim Aufruf f2( &i ) ist *p_i keine Konstante, auch wenn es in f2() so 
deklariert ist, sondern eine astreine Variable - sie wird nur in f2() 
nicht geändert.

von Rolf Magnus (Gast)


Lesenswert?

Klaus Wachtler schrieb:
> Dosmo schrieb:
>> const int a; ist eine Konstante.const int *a; ist ein (variabler)
>> Zeiger auf eine Konstante.
>
> Jein.
> Genau genommen ist es eine Variable und mit dem const sagt man, daß man
> im Geltungsbereich dieser Deklaration diese Variable nicht ändern
> möchte.

Noch genauer genommen gibt es in C gar keine Konstanten (abgesehen von 
direkt als Zahl hingeschriebenen Werten). Das ist ja der Grund, warum so 
oft Makros als Ersatz dafür verwendet werden.

von j.v. (Gast)


Lesenswert?

Decius schrieb:
> Aber Systemabhängig muß das ganze aber auch sein. Denn die Byteweiyse
> Addressierung der intelplattform ist bei ARM's nicht üblich.
>

Sie ist üblich.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Klaus Wachtler schrieb:

> void f2( const int * p_i )
> {
>    // jetzt nicht mehr möglich: *p_i++;
> }

Doch, *p_i++ geht sehr wohl, weil das *p_i nicht verändert.

Was hingegen nicht geht ist (*p_i)++.

von Dosmo (Gast)


Lesenswert?

Klaus Wachtler schrieb:
> Dosmo schrieb:
>> const int a; ist eine Konstante.const int *a; ist ein (variabler)
>> Zeiger auf eine Konstante.
>
> Jein.
> Genau genommen ist es eine Variable und mit dem const sagt man, daß man
> im Geltungsbereich dieser Deklaration diese Variable nicht ändern
> möchte.

Absolut richtig.
Mir ging es um den Unterschied, ob man den Qualifier vor oder hinter den 
* setzt.

von Klaus W. (mfgkw)


Lesenswert?

Johann L. schrieb:
> Klaus Wachtler schrieb:
>
>> void f2( const int * p_i )
>> {
>>    // jetzt nicht mehr möglich: *p_i++;
>> }
>
> Doch, *p_i++ geht sehr wohl, weil das *p_i nicht verändert.
>
> Was hingegen nicht geht ist (*p_i)++.

ja, meinte ich natürlich.

von Rolf M. (rmagnus)


Lesenswert?

Dosmo schrieb:
> Absolut richtig.
> Mir ging es um den Unterschied, ob man den Qualifier vor oder hinter den
> * setzt.

Generell bezieht sich der Qualifier auf das, was unmittelbar links davon 
steht. Und dann gibt es noch den Spezialfall, daß links nichts mehr 
kommt. Dann bezieht er sich stattdessen auf das, was unmittelbar rechts 
davon steht.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Dosmo schrieb:

> Mir ging es um den Unterschied, ob man den Qualifier vor oder hinter den
> * setzt.

In Gedanken trennt man die Deklaration in durch * getrennte Häppchen 
auf. Ein Qualifier wirkt nur auf sein eigenes Häppchen.

Damit ist auch klar, wie welcher Zugriff geschieht in
1
char f (const __flash char * const volatile __flash ** volatile * const p)
2
{
3
    return ****p;
4
}

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.