Pointerfehler, warum nur?

Gast #3063956
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
#3063981
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!
#3063987
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.
Gast #3063995
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
#3063999
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.
#3064003
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.
#3064018
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.
#3064054
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
#3064104
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren