mikrocontroller.net

Forum: PC-Programmierung Zeiger auf array-Element: Inkrement WTF?


Autor: Uhrenmännchen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin,

ich probiere mich gerade in der ARM-Programmierung und ich habe den 
folgenden Code geschrieben:

const uint8_t cursorBitmap[] = {
    8, 8, 0x7F, 0x7F, 0x00, 0x7F, 0x7F, 0x3E, 0x1C, 0x08, // >
    8, 8, 0x08, 0x1C, 0x3E, 0x7F, 0x7F, 0x00, 0x7F, 0x7F // <
};


int main(void)
{
    putBitmap(&(cursorBitmap)+ 10);
    putBitmap(&cursorBitmap[10]);

    while(1);
    return 0;
}
Programmiert wird mit dem GCC. Wenn ich mich mit dem Debugger in die 
Funktion einklinke, wird sie einmal mit dem Parameter "10" und einmal 
mit dem Parameter "20" aufgerufen, obwohl sie eigentlich beide Mal den 
gleichen Parameter haben sollte!!!

Was passiert hier???

: Verschoben durch Moderator
Autor: Dr. Sommer (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Uhrenmännchen schrieb:
> putBitmap(&(cursorBitmap)+ 10);
Ist falsch, es muss "cursorBitmap + 10" sein.

Autor: Uhrenmännchen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dr. Sommer schrieb:
> Ist falsch, es muss "cursorBitmap + 10" sein.

Ja, das macht Sinn. Danke!!!!!

Autor: Stefan Us (stefanus)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
cursorBitmap[] ist das Array von Bytes.
cursorBitmap liefert die Adresse des Arrays.

&cursorBitmap ergibt für mich nicht wirklich Sinn, da cursorBitmap 
bereits die Adresse des Arrays liefert.

cursorBitmap+10 addiert 10 zum Zeiger auf das Array. Wenn die Bytes ohne 
Lücke/Füllbytes ausgerichtet sind (das ist meistens so, muss aber nicht 
zwingend der Fall sein, siehe Compiler Optionen), dann erhälst du so 
einen Zeiger auf das elfte Element des Arrays.

cursorBitmap[10] liefert den Wert des elften Elementes des Arrays, egal 
wie die Daten ausgerichtet sind.

&cursorBitmap[10] liefert die Adresse des elften Elementes des Array, 
egal wie die Daten ausgerichtet sind.

Autor: Dr. Sommer (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Das stimmt nicht ganz, "&cursorBitmap[10]" ist immer absolut identisch 
zu "cursorBitmap + 10", vollkommen unabhängig von 
Ausrichtung/Padding/Größe der Elemente. Der Compiler rechnet hier 
Basisadresse + sizeof(Element) * 10.
Arrays selbst haben gar kein Padding, das wurde hier schon besprochen: 
Beitrag "Re: 32 Bitter: Einen Array packen"
Höchstens die Elemente selbst können Füllbytes enthalten, was sich auch 
in sizeof() niederschlägt.

Autor: Stefan Us (stefanus)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Danke für die Aufklärung.
Viel interessanter fände ich eine Erklärung, was denn

> &cursorBitmap

bewirken soll. Ich habe keine Ahnung, aber ein zufälliges Ergebnis wird 
wohl kaum dabei heraus kommen.

: Bearbeitet durch User
Autor: MaWin (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Stefan U. schrieb:
> Wenn die Bytes ohne
> Lücke/Füllbytes ausgerichtet sind (das ist meistens so, muss aber nicht
> zwingend der Fall sein, siehe Compiler Optionen),

Doch, das muss zwingend so sein bei arrays.

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Stefan U. schrieb:
> Viel interessanter fände ich eine Erklärung, was denn
>
>> &cursorBitmap
>
> bewirken soll.

Im Ausdruck cursorBitmap+10 ist cursorBitmap ein Zeiger auf uint8_t,
entsprechend wird bei der Adressberechnung die 10 mit sizeof(uint8_t)=1
multipliziert.

In &cursorBitmap+10 ist cursorBitmap ein Zeiger auf uint8_t[20] (das
Array hat auf Grund der Initialisierung 20 Werte). Die 10 wird nun nicht
mit 1, sondern mit sizeof(uint8_t[20])=20 multipliziert.

&cursorBitmap+10 zeigt somit auf eine Position, die 200 Bytes nach dem
Arrayanfang liegt. Da das Array selbst nur 20 Byte groß ist, bewirkt
eine Dereferenzierung des Ergebniszeigers undefiniertes Verhalten.

Autor: Stefan Us (stefanus)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Mannomann, C hat ja echt ein paar gemeine Fallstricke. Aber man muss 
entschuldigend berücksichtigen, wie alt diese Sprache ist.

Autor: Daniel H. (Firma: keine) (commander)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Stefan U. schrieb:
> Mannomann, C hat ja echt ein paar gemeine Fallstricke. Aber man muss
> entschuldigend berücksichtigen, wie alt diese Sprache ist.

Das hat nichts mit dem Alter der Sprache zu tun, wie bei jeder anderen 
Sprache auch muss man eben wissen, was man tut.

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Stefan U. schrieb:
> Mannomann, C hat ja echt ein paar gemeine Fallstricke.

So arg fallstrickig ist das gar nicht, da der GCC hier in mindestens
einer der beiden putBitmap-Zeilen eine Warnung ausgibt (die natürlich
nur dann einen Nutzen hat, wenn sie auch gelesen wird ;-)). Ich vermute,
putBitmap ist als

void putBitmap(const uint8_t *bm);

oder so ähnlich deklariert. Wird als Argument &cursorBitmap[10] oder
cursorBitmap+10 übergeben, passt der Datentyp. Bei &cursorBitmap+10
hingegen beschwert sich der Compiler zurecht:

expected ‘const uint8_t * {aka const unsigned char *}’ but argument
is of type ‘const uint8_t (*)[20] {aka const unsigned char (*)[20]}’

Autor: Uhrenmännchen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Yalu X. schrieb:
> In &cursorBitmap+10 ist cursorBitmap ein Zeiger auf uint8_t[20] (das
> Array hat auf Grund der Initialisierung 20 Werte). Die 10 wird nun nicht
> mit 1, sondern mit sizeof(uint8_t[20])=20 multipliziert.

Diese Logik ist gewöhnungsbedürftig, aber logisch.

Yalu X. schrieb:
> (die natürlich
> nur dann einen Nutzen hat, wenn sie auch gelesen wird ;-)).

Es gibt auch eine Warnung, nämlich
"warning: passing argument 1 of 'putBitmap' discards 'const' qualifier 
from pointer target type [-Wdiscarded-qualifiers]", (was er allerdings 
in allen Zeilen, wo putBitmap() aufgerufen wird, tut, da
void putBitmap(uint8_t *bm);
Ich muß das mal mit dem LLC ausprobieren, vielleicht ist der 
geschwätziger.

Autor: Dr. Sommer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Uhrenmännchen schrieb:
> Ich muß das mal mit dem LLC ausprobieren, vielleicht ist der
> geschwätziger.

Oder mal -Wall -Wextra an den GCC übergeben. Sollte man während der 
Entwicklung sowieso immer tun.

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dr. Sommer schrieb:
> Oder mal -Wall -Wextra an den GCC übergeben. Sollte man während der
> Entwicklung sowieso immer tun.

Beim GCC (7.2.0) und Clang (5.0.0) ist die Warnung defaultmäßig
aktiviert und kann ggf. mit -Wno-incompatible-pointer-types unterdrückt
werden. Die const-Warnung wird zusätzlich ausgegeben, wenn das const in
der Deklaration von putBitmap fehlt.

In C++ sind sowohl der falsche Zeigertyp als auch die const-Verletzung
echte Fehler und werden deswegen als Error ausgegeben.

Autor: Rolf Magnus (rmagnus)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Stefan U. schrieb:
> cursorBitmap[] ist das Array von Bytes.
> cursorBitmap liefert die Adresse des Arrays.

Nein. Es liefert die Adresse des ersten Array-Elements. Das ist zwar die 
selbe Speicherstelle, auf die gezeigt wird, aber der Datentyp ist ein 
anderer.

> cursorBitmap+10 addiert 10 zum Zeiger auf das Array.

Nein, das wäre das, was &cursorBitmap+10 macht. Man müsste dann 10 
solche Arrays haben, und der Zeiger würde dann auf das elfte Array 
zeigen. cursorBitmap+10 addiert 10 zum Zeiger auf das erste Element und 
zeigt deshalb auf das elfte Element des Arrays.

> Wenn die Bytes ohne Lücke/Füllbytes ausgerichtet sind (das ist meistens
> so, muss aber nicht zwingend der Fall sein, siehe Compiler Optionen),
> dann erhälst du so einen Zeiger auf das elfte Element des Arrays.

Das ist nicht meistens so, sondern immer. Füllbytes kann es geben, die 
sind aber Teil des Element-Typs. Zwischen den Array-Elementen darf es in 
C keine Lücke geben. Deshalb erhält man immer einen Zeiger auf das elfte 
Element.

Uhrenmännchen schrieb:
> Yalu X. schrieb:
>> In &cursorBitmap+10 ist cursorBitmap ein Zeiger auf uint8_t[20] (das
>> Array hat auf Grund der Initialisierung 20 Werte). Die 10 wird nun nicht
>> mit 1, sondern mit sizeof(uint8_t[20])=20 multipliziert.
>
> Diese Logik ist gewöhnungsbedürftig, aber logisch.

Ja, logische Logik ist was tolles. ;-)

Daniel H. schrieb:
>> Mannomann, C hat ja echt ein paar gemeine Fallstricke. Aber man muss
>> entschuldigend berücksichtigen, wie alt diese Sprache ist.
>
> Das hat nichts mit dem Alter der Sprache zu tun, wie bei jeder anderen
> Sprache auch muss man eben wissen, was man tut.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.