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


von Uhrenmännchen (Gast)


Lesenswert?

Moin,

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

1
const uint8_t cursorBitmap[] = {
2
    8, 8, 0x7F, 0x7F, 0x00, 0x7F, 0x7F, 0x3E, 0x1C, 0x08, // >
3
    8, 8, 0x08, 0x1C, 0x3E, 0x7F, 0x7F, 0x00, 0x7F, 0x7F // <
4
};
5
6
7
int main(void)
8
{
9
    putBitmap(&(cursorBitmap)+ 10);
10
    putBitmap(&cursorBitmap[10]);
11
12
    while(1);
13
    return 0;
14
}
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
von Dr. Sommer (Gast)


Lesenswert?

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

von Uhrenmännchen (Gast)


Lesenswert?

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

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

von Stefan F. (Gast)


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.

von Dr. Sommer (Gast)


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.

von Stefan F. (Gast)


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.

von MaWin (Gast)


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.

von Yalu X. (yalu) (Moderator)


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.

von Stefan F. (Gast)


Lesenswert?

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

von Daniel H. (Firma: keine) (commander)


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.

von Yalu X. (yalu) (Moderator)


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

1
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:

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

von Uhrenmännchen (Gast)


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
1
void putBitmap(uint8_t *bm);
Ich muß das mal mit dem LLC ausprobieren, vielleicht ist der 
geschwätziger.

von Dr. Sommer (Gast)


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.

von Yalu X. (yalu) (Moderator)


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.

von Rolf M. (rmagnus)


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.

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.