Forum: Mikrocontroller und Digitale Elektronik Pointerfehler, warum nur?


von Ingo (Gast)


Lesenswert?

Hallo,

ich habe folgende Funktion:
1
void Read_Flash ( int* DataArrayToBeFilled, int SizeOfArray )
2
{
3
  int *pointer;
4
  if ( SizeOfArray > ARRAYSIZE_MAX ){
5
    SizeOfArray = ARRAYSIZE_MAX;
6
  }
7
8
  for ( int i = 0; i < SizeOfArray ; i++ ){
9
    pointer = SECTOR11_STARTADRESS + i * (sizeof ( int ) ); // Hier die Warnung!
10
    DataArrayToBeFilled[ i ] = *pointer;
11
  }
12
}

ich bekommen aber eine Warnung von wegen
warning: assignment makes pointer from integer without a cast [enabled 
by default]
aber warum? Ich übergebe dem Pointer eine Zahl, diese ist eine Adresse. 
Gut, das weiß jetzt der Kompiler ja nicht, kommt deswegen die Warnung 
bzw. wie kann ich sie vermeiden?

Ich nutze die CooIDE auf einem STM32F4

Ingo

von (prx) A. K. (prx)


Lesenswert?

Im ersten Ansatz:
pointer = (int *)(SECTOR11_STARTADRESS + i * (sizeof ( int ) ));

Besser:
pointer = (int *)SECTOR11_STARTADRESS + i;

von Davis (Gast)


Lesenswert?

Der Pointer möchte keine Zahl,der Pointer möchte eine Adresse. Alles 
weitere teilt dir ein gutes C-Buch mit.

von Dominic (Gast)


Lesenswert?

Ja, das sagt die Warnung ja schon. Du musst einen expliziten Typecast 
machen:
1
pointer = (int *)(SECTOR11_STARTADRESS + i * (sizeof ( int )));

von Karl H. (kbuchegg)


Lesenswert?

Ingo schrieb:

>     pointer = SECTOR11_STARTADRESS + i * (sizeof ( int ) ); // Hier die
> Warnung!


Wie ist SECTOR11_STARTADRESS definiert?

von Ingo (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Wie ist SECTOR11_STARTADRESS definiert?
1
#define SECTOR11_STARTADRESS  0x080C0000

Dominic schrieb:
1
pointer = (int *)(SECTOR11_STARTADRESS + i * (sizeof ( int )));

Ahh, ja, der Cast zu einer Adresse, danke!



Ingo

von Ingo (Gast)


Lesenswert?

Davis schrieb:
> Alles weitere teilt dir ein gutes C-Buch mit.
Also im C&R wird sich über das direkte Setzen einer Adresse, also nicht 
über den &variable - operator, leider aus geschwiegen.


Ingo

von Karl H. (kbuchegg)


Lesenswert?

Ingo schrieb:
> Karl Heinz Buchegger schrieb:
>> Wie ist SECTOR11_STARTADRESS definiert?
>
1
> #define SECTOR11_STARTADRESS  0x080C0000
2
>
>
> Dominic schrieb:
>
1
> pointer = (int *)(SECTOR11_STARTADRESS + i * (sizeof ( int )));
2
>
>
> Ahh, ja, der Cast zu einer Adresse, danke!


Die Frage ist aber eher, warum SECTOR11_STARTADRESS nicht von vorne 
herein bereits eine Adresse ist (ein Pointer), sondern ein stink 
normaler Integer. Die Makro-Konstante hat ja in ihrem Namen schon den 
Zusatz 'ADRESS' (Adresse schreibt sich im Englischen übrigens mit 
Doppel-d), ist aber keine Adresse!

Sowas ist nicht gut. Achte mehr auf Konsistenz zwischen dem was deine 
Namen im Programm aussagen, und was sie tatsächlich sind - welche 
Datentypen dahinter stecken!


Wird SECTOR11_STARTADRESS  immer im Sinne von 'Pointer auf Integer' 
benutzt?
Wenn ja, dann
1
#define SECTOR11_STARTADRESS  ((int*)0x080C0000)

und dafür im Code
1
  for ( int i = 0; i < SizeOfArray ; i++ ){
2
    DataArrayToBeFilled[ i ]= SECTOR11_STARTADRESS[ i ];
3
  }


Oder ist SECTOR11_STARTADRESS  eher als allgemeiner Pointer in den 
Speicher anzusehen, an dem Bytes liegen. Wenn ja, dann
1
#define SECTOR11_STARTADRESS  ((unsigned char*)0x080C0000)

und im Code dann
1
  for ( int i = 0; i < SizeOfArray ; i++ ){
2
    DataArrayToBeFilled[ i ]= ((int*)SECTOR11_STARTADRESS)[ i ];
3
  }

Aber auf jeden Fall sollte etwas, was im Namen schon 'ADDRESS' im Sinne 
einer Speicheradresse trägt, dann auch tatsächlich erst mal ein Pointer 
sein und kein Integer!

von Karl H. (kbuchegg)


Lesenswert?

Ingo schrieb:
> Davis schrieb:
>> Alles weitere teilt dir ein gutes C-Buch mit.
> Also im C&R wird sich über das direkte Setzen einer Adresse, also nicht
> über den &variable - operator, leider aus geschwiegen.

Komisch.
Als ich das letzte mal den K&R gelesen habe, war ein Viertel Buch voll 
mit Erklärungen zu Datentypen und Castings.


Datentypen sind nicht dazu da, um den Programmierer zu ärgern.

ein 5 ist nun mal ein Integer und kein Pointer.

von Ingo (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Die Frage ist aber eher, warum SECTOR11_STARTADRESS nicht von vorne
> herein bereits eine Adresse ist (ein Pointer), sondern ein stink
> normaler Integer

Weil ich eine weitere Funktion aus der Lib habe, die als Adresse 
tatsächlich einen uint32_t erwartet, keine Adresse.

von Ingo (Gast)


Lesenswert?

die da heisst:
1
FLASH_ProgramWord( SECTOR11_STARTADDRESS + i * sizeof ( int ) , DataArrayToBeStored[i] );

mit
1
FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data);

Wenn ich das so mache wie vorgeschlagen bekomme ich hier die Warnung, 
ich würde aber ungern die Lib ändern. ich bleibe dann lieber bei einem 
Cast zur Adresse.


Ingo

von Karl H. (kbuchegg)


Lesenswert?

Ingo schrieb:
> Karl Heinz Buchegger schrieb:
>> Die Frage ist aber eher, warum SECTOR11_STARTADRESS nicht von vorne
>> herein bereits eine Adresse ist (ein Pointer), sondern ein stink
>> normaler Integer
>
> Weil ich eine weitere Funktion aus der Lib habe, die als Adresse
> tatsächlich einen uint32_t erwartet, keine Adresse.

Das ist für mich ehrlich gesagt kein Argument.
Denn wenn die Funktion die 4 Bytes als float überhmen würde, dann 
würdest du da ja auch keinen Float definieren.

Die Funktion will nur sicher stellen, dass du dir darüber im klaren 
bist, dass diese Adresse in Form von 4 Bytes angegeben wird (und nicht 
mit 2 Bytes oder mit 8 Bytes). Daher der uint32_t.
Das ändert aber nichts daran, dass in DEINEM Programm, in DEINEM Code, 
SECTOR11_STARTADRESS die Funktion eines Pointers hat. Sonst würde es ja 
nicht 'xxxADDRESS' heißen.

von Karl H. (kbuchegg)


Lesenswert?

Ingo schrieb:
> die da heisst:
>
1
> FLASH_ProgramWord( SECTOR11_STARTADDRESS + i * sizeof ( int ) ,
2
> DataArrayToBeStored[i] );
3
>
>
> mit
>
1
> FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data);
2
>
>
> Wenn ich das so mache wie vorgeschlagen bekomme ich hier die Warnung,

natürlich:

denn: ein Pointer ist kein Integer und ein Integer ist kein Pointer. 
Datentyppmässig gesehen.


> ich würde aber ungern die Lib ändern.

Sagt ja auch keiner

> ich bleibe dann lieber bei einem
> Cast zur Adresse.

Ja. An dieser Stelle, beim Aufruf dieser Funktion musst du casten. Das 
ist nicht so ungewöhnlich, dass man an den Schnittstellen nach aussen 
seine 'Variablen' zurechtcasten muss. Aber das ist kein Argument, dass 
man sein ganzes Programm rund um diese von der Schnittstelle 
vorgegebenen Datentypen aufbaut. Zuallererst sind die Innereien DEINES 
Codes wichtig und nicht das, was dir eine zugekaufte Lib aufs Auge 
drückt.

von Ingo (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Ja. An dieser Stelle, beim Aufruf dieser Funktion musst du casten. Das
> ist nicht so ungewöhnlich, dass man an den Schnittstellen nach aussen
> seine 'Variablen' zurechtcasten muss.
Ok, gut zu wissen. Vielen Dank.

@Würg Jonsch
Fast drauf reingefallen ;)




Ingo

von Ingo (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Zuallererst sind die Innereien DEINES
> Codes wichtig und nicht das, was dir eine zugekaufte Lib aufs Auge
> drückt.
Du hast ja recht, wenn von Address die Rede ist, sollte sich dahinter 
auch eine "echte" Adresse verbergen.


Ingo

von Karl H. (kbuchegg)


Lesenswert?

So wie es aussieht, hast du es anscheinend eh immer mit int zu tun.

d.h. deine Makro könnte so aussehen
1
#define SECTOR11_STARTADRESS  ((int*)0x080C0000)

d.h. SECTOR11_STARTADRESS  ist die Startadresse, an der ein Haufen int 
beheimatet ist.

d.h. der Aufruf sieht dann so aus:
1
  FLASH_ProgramWord( (uint32_t)&SECTOR11_STARTADDRESS[i], DataArrayToBeStored[i] );

Und ich finde, das ist doch eigentlich gut zu lesen. Man nehme die 
Position des i-ten int im 'Array', welches bei SECTOR11_STARTADDRESS 
beginnt (aus technischen Gründen muss diese Adresse zu einem uint32_t 
gecastet werden) und an dieser Adresse wird dann der Wert von 
DataArrayToBeStored[i] abgelegt. Sieht alles gut aus. Die beiden 
'Arrayzugriffe' sind identisch und überzeugt mich insofern, dass das in 
Ordnung ist.

Wenn ich dann noch die Sicherheitskarte ausspielen will, dann mach ich 
mir eine Zwischenfunktion, die geinlined wird
1
inline void FLASH_ProgrammInt( int* Addr, int Value )
2
{
3
  FLASH_ProgramWord( (uint32_t)Addr, Value );
4
}
und deren einziger Zweck es ist, mir Typsicherheit zu geben und den 
Cast, den mir die Lib aufs Auge drückt an einer Stelle zu kanalisieren. 
Im meinem Code benutze ich fortan nur noch FLASH_ProgrammInt um zu 
schreiben
1
  FLASH_ProgramInt( &SECTOR11_STARTADDRESS[i], DataArrayToBeStored[i] );

dann hab ich sogar noch die Typsicherheit, weil der Compiler mich die 
Funktion nur mit einem int-Pointer aufrufen lässt.

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


Lesenswert?

Worauf interessanterweise noch gar keiner eingegangen ist, was aber IMHO 
immens wichtig ist, das ist der Unterschied zwischen int-Arithmetik 
und Pointerarithmetik.

Gehen wir mal aus vom originalen
1
#define SECTOR11_STARTADRESS  0x080C0000

und ferner von einer Plattform mit sizeof(int) != 1

Dann verhalten sich die folgenden 3 Codeschnipsel identisch:
1
int i = 42;
2
int x = ((int*)SECTOR11_STARTADRESS)[i];
1
int i = 42;
2
int x = *((int*)SECTOR11_STARTADRESS + i);
1
int i = 42;
2
int x = *((int*)(SECTOR11_STARTADRESS + i*sizeof(int)));

das bereits vorgeschlagene
1
int i = 42;
2
int x = *((int*)SECTOR11_STARTADRESS + i*sizeof(int));

ist hingegen falsch.

http://www.google.com/search?q=pointer-arithmetik


XL


Edit: im ersten Beispiel fehlte eine explizite Klammer. [] bindet 
stärker als der Cast, deswegen gehören da Klammern um 
(int*)SECTOR11_STARTADRESS

von Walter S. (avatar)


Lesenswert?

dein Beitrag ist zwar korrekt,
aber wo hat den jemand das untenstehende vorgeschlagen?

Axel Schwenke schrieb:
> das bereits vorgeschlagene
> int i = 42;
> int x = *((int*)SECTOR11_STARTADRESS + i*sizeof(int));
>
> ist hingegen falsch.

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


Lesenswert?

Walter S. schrieb:
> dein Beitrag ist zwar korrekt,
> aber wo hat den jemand das untenstehende vorgeschlagen?

Hmm. Da habe ich wohl eine Klammer in Dominic (gast) 4. Post übersehen. 
Mea culpa!

Bei mir geht eine Warnlampe an, wenn ich Manipulation von Pointern oder 
pointerartigen Variablen sehe, die sizeof() beinhalten. Die explizit 
verschiedenen Pointertypen wurden ja gerade deswegen eingeführt, damit 
man sizeof() nicht mehr braucht.

Das tatsächliche Problem ist die lib-Funktion, die als Adresse im Flash 
ein uint_32t sehen will. Ein void* wäre angemessen gewesen.


XL

von (prx) A. K. (prx)


Lesenswert?

Axel Schwenke schrieb:
> Worauf interessanterweise noch gar keiner eingegangen ist,

Doch.

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.