Forum: Compiler & IDEs Problem mit SDCC


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Thomas Z. (usbman)


Lesenswert?

Ich benutze in der Regel Keil c51, habe mir aber angewöhnt meinen Code 
auch für SDCC kompatibel zu machen. Die Unterschiede löse ich mit ein 
paar macros.
Bisher hatte ich v3.9 installiert nun aber ein Update auf v4.4 gemacht. 
Da die Jungs inzwischen wieder mal am Parser gespielt haben lassen sich 
alte Programme nicht mehr übersetzen, das sind aber Kleinigkeiten die 
sich einfach lösen lassen. Gut ist dass sich das CBYTE macro aus Keils 
<absacc.h> nun auch im SDCC fehlerfrei benutzen lässt. ( #define CBYTE 
((uint8_t volatile CODE  *) 0) )

Dieses reduzierte Programm wirft eine warning:
warning 196: pointer target lost const qualifier in Zeile 14.
1
#include <stdint.h>
2
3
__code uint8_t DevDesc[18] = { 0x12,0x01,0x10,0x01,0xFF,0x00,0x00,0x08,
4
                               0xC0,0x16,0xDC,0x05,0x00,0x10,0x01,0x02,
5
                               0x03,0x10 };
6
7
__xdata __at (0x0000) uint8_t  EP0_Buffer[0x08 + 2];
8
9
uint8_t *ptr;
10
11
void main (void)
12
{
13
   uint8_t i;
14
   ptr = &DevDesc[0];
15
   for (i= 0;i<8;i++) 
16
      EP0_Buffer[i] = *ptr++;
17
18
   while(1) {}   
19
}

Die warning bekommt man relativ einfach weg wenn man const uint8_t *ptr 
schreibt. Soweit so gut. Ich habe mich aber ganz bewusst gegen const auf 
den generic Pointer entschieden weil ich auch schreibend zugreifen muss. 
Das geht natürlich nicht mit const.

Der generierte code ist ok und funktioniert, ich mag allerdings keine 
Warnings da diese sehr oft eben doch auf ein Problem hinweisen. Ich 
halte die warning für einen Bug. Die kommt übrigens auch bei v3.9. Keil 
übersetzt das ohne zu meckern.

Was meint Ihr? Mach ich da einen Fehler oder ist das ein Bug im SDCC?

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Du konvertierst ein "const uint8_t*" nach "uint8_t*", das gibt in jedem 
Compiler für jede Plattform eine Warning (zu Recht).

Thomas Z. schrieb:
> Ich habe mich aber ganz bewusst gegen const auf
> den generic Pointer entschieden weil ich auch schreibend zugreifen muss.

Du überschreibst den Device-Deskriptor im Flash? Über eben diesen 
Pointer?

von Thomas Z. (usbman)


Lesenswert?

Niklas G. schrieb:
> Du konvertierst ein "const uint8_t*" nach "uint8_t*", das gibt in jedem
> Compiler für jede Plattform eine Warning (zu Recht).

ich könnte das verstehen wenn da stehen würde
1
const __code uint8_t DevDesc[18]
Der Compiler scheint aus __code automatisch const __code zu machen. 
Trotzdem ist es doch legal einem generic Pointer ein Array aus dem Flash 
zuzuweisen.

> Du überschreibst den Device-Deskriptor im Flash? Über eben diesen
> Pointer?
natürlich nicht. Wie sollte das auch gehen? Ich benutze den Pointer halt 
an anderer Stelle auch schreibend.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Thomas Z. schrieb:
> Der Compiler scheint aus __code automatisch const __code zu machen.

Das macht auch Sinn denke ich, damit man nicht versehentlich versucht da 
drauf zu schreiben.

Thomas Z. schrieb:
> Trotzdem ist es doch legal einem generic Pointer ein Array aus dem Flash
> zuzuweisen.

Wenn das einfach so ginge könntest du sehr einfach versehentlich in den 
Flash "schreiben" (weiß nicht was der 8051 dann macht, Absturz?).

Thomas Z. schrieb:
> Ich benutze den Pointer halt
> an anderer Stelle auch schreibend.

Benutz halt einen anderen Pointer? Holzhammermethode: Eine "union" mit 
"const" und "nicht-const" Pointer. Oder halt manuell auf "uint8_t*" 
casten.

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Niklas G. schrieb:
> Oder halt manuell auf "uint8_t*"
> casten.

Das hilft zwar, deutet aber halt zusammen mit

Thomas Z. schrieb:
> Ich benutze den Pointer halt
> an anderer Stelle auch schreibend.

auf ein vermeidbares „Ich schiesse mir von der Brust durchs Knie ins 
Auge“-Problem hin.

Sauber gelöst, würde das alles nicht nötig sein.

Oliver

von Klaus S. (kseege)


Lesenswert?

Thomas Z. schrieb:
> Was meint Ihr? Mach ich da einen Fehler oder ist das ein Bug im SDCC?

Als langjähriger ASM-Programmierer der 8051-Familie würde ich mir 
natürlich erstmal den generierten Code ansehen, dann wüßte man mehr.
Meine Vermutung ist, daß es sich um eine Warnung vor einer eventuellen 
Fehlermöglichkeit handelt. Der deklarierte Pointer steht im internen RAM 
und kann benutzt werden, um auf internes und externes RAM sowie auf ROM 
zuzugreifen. Auf ROM kann man eben (mit movc) nur lesend zugreifen und 
nicht schreibend, das ist m.E. die potentielle Fehlermöglichkeit, die 
später als error aufschlagen kann.

Schreibt man das Ganze ohne Pointer, solte es ohne Warnung durchgehen.
EP0_Buffer[i] = DevDesc[i];

Gruß Klaus

von Klaus S. (kseege)


Lesenswert?

Ansonsten sollte eigentlich (nach meinen unperfekten C-Kentnissen) ein 
umcasten helfen:
EP0_Buffer[i] = (_xdata uint8_t)(*ptr++);

Gruß Klaus

von Klaus S. (kseege)


Lesenswert?

Thomas Z. schrieb:
> ptr = &DevDesc[0];

Bei mir scheint heute der Euro nur cent-weise zu fallen. Natürlich 
gehört da korrekterweise ebenfalls ein cast hin, bin aber nich ganz 
sattelfest, wie der aussehen muß. Der 8051 hat nun mal 3 
unterschiedliche Adreßräume und der korrekte Typ muß für einen Pointer 
per cast angegeben werden, wenn es nicht der definierte (in diesem Fall 
auf inernes RAM) ist.

Gruß Klaus

von Thomas Z. (usbman)


Lesenswert?

Klaus S. schrieb:
> Als langjähriger ASM-Programmierer der 8051-Familie würde ich mir
> natürlich erstmal den generierten Code ansehen
Hab ich das passt schon. Ist ja auch nur eine warning. Der code wird 
korrekt erzeugt mit MOVC.

Wie gesagt Keil c51 übersetzt das ohne Murren. Tatsächlich ist die ptr 
Variable nicht global sondern in einer Interrupt Funktion lokal 
definiert
1
static uint8_t *ptr;
Das spielt für Warnung aber keine Rolle. Üblicherweise arbeite ich nur 
mit Keil und teste manchmal mit SDCC wenn der code veröffentlicht werden 
soll.

von Peter D. (peda)


Lesenswert?

Thomas Z. schrieb:
> Ich benutze den Pointer halt
> an anderer Stelle auch schreibend.

Ich würde local verwendete Pointer auch local definieren. Dann könnte 
der Compiler sie in Register optimieren (kürzere Befehle, weniger SRAM) 
oder mit anderen temporären Variablen überlagern.

Man kann auch den Pointer ganz weglassen und über den Schleifenzähler 
als Index auf das Element zugreifen. Dann kann sich der Compiler selber 
überlegen, wie er das optimiert.

Globale Variablen nimmt man nur, wenn sie auch funktionsübergreifend 
ihren Wert behalten müssen.

von Peter D. (peda)


Lesenswert?

Thomas Z. schrieb:
> Tatsächlich ist die ptr
> Variable nicht global sondern in einer Interrupt Funktion lokal
> definiert

Dann würde ich erst recht nicht mit dem Hammer "generic Pointer" 
draufschlagen, sondern memory spezific Pointer nehmen.
Hast Du Dir mal den erzeugten Code dafür angesehen?

von Thomas Z. (usbman)


Lesenswert?

Peter D. schrieb:
> Globale Variablen nimmt man nur, wenn sie auch funktionsübergreifend
> ihren Wert behalten müssen.

Der wert muss erhalten bleiben da ich immer nur Teile des Deskriptors 
pro Aufruf zurück geben kann. Deswegen auch die Deklaration als static 
in der Interrupt Funktion.

> Dann würde ich erst recht nicht mit dem Hammer "generic Pointer"
> draufschlagen, sondern memory spezific Pointer nehmen.

generic ist notwendig weil einige wenige Descriptoren im Ram liegen. 
(z.B. Seriennummer). Mir ist klar, dass der Zugriff über lib Funktionen 
passiert
und deswegen etwas mehr code erzeugt wird. Wie angemerkt funktioniert 
das mit Keil ohne Warnung. Der SDCC erzeugt halt ohne const diese 
Warnung.

von Peter D. (peda)


Lesenswert?

Thomas Z. schrieb:
> generic ist notwendig weil einige wenige Descriptoren im Ram liegen.

Ist natürlich schwer nachzuvollziehen, da keiner den wirklichen Code 
kennt.
Ich würde die 18 Bytes mit in XDATA legen, ist ja nicht so viel. Sind es 
zusammen <256 Byte, dann muß der Compiler auch nur 1 Byte Index sichern, 
statt 3 Byte generic Pointer.

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.