Forum: Mikrocontroller und Digitale Elektronik Integer promotion - Ich raff's nicht


von Walter T. (nicolas)


Lesenswert?

Hallo zusammen,
ich sitze hier mit dem K&R und wundere mich. Im folgenden Quelltext:
1
static inline __attribute__((always_inline)) void
2
ClearBit(GPIO_TypeDef * const GPIOx, const uint16_t bit) 
3
{
4
    GPIOx->BSRR = bit<<16U;
5
}
warnt mich der ARM-GCC zu der einzigen aktiven Zeile:
"30: warning: conversion to 'uint32_t' from 'int' may change the sign of 
the result [-Wsign-conversion]"

Das Feld "BSRR" ist übrigens als Zeiger auf uint32_t deklariert.

OK, was passiert hier? "bit" paßt in einen 32-Bit-Integer, wird also in 
einen solchen konvertiert. 16U passt nicht hinein und bleibt deshalb ein 
unsigned int. Um die Schiebeoperation durchführen zu können, wird 
anschließend "bit" vom Int -in das es vorher konvertiert wurde- in ein 
unsigned Int konvertiert - hier tritt der mögliche Datenverlust auf und 
der GCC warnt mich.

Mit der Änderung
1
GPIOx->BSRR = (uint32_t) bit<<16U;
wird "bit" direkt passend kovertiert und der Zwischenschritt über einen 
signed integer bleibt aus. Habe ich das richtig verstanden?

Viele Grüße
W.T.

von Ja (Gast)


Lesenswert?

>Habe ich das richtig verstanden?

Ja

von asdfasd (Gast)


Lesenswert?

> "bit" paßt in einen 32-Bit-Integer, wird also in  einen solchen konvertiert.

Nein.  Integer-Arithmetik findet immer in mindesten int-Größe statt (wie 
groß auch immer das ist).  bit (ein uint16_t) ist auf ARM kleiner als 
int (32 Bit), also wird es zu int erweitert.  Auf Systemen mit 
16-Bit-Ints bliebe es ein uint16_t.

> 16U passt nicht hinein und bleibt deshalb ein unsigned int.

Ist egal, ist ein (unsigned) int, bleibt auch einer.  Btw, das U ist 
unnötig.

> Um die Schiebeoperation durchführen zu können, wird anschließend "bit" vom
> Int -in das es vorher konvertiert wurde- in ein  unsigned Int konvertiert

Nein, der int-Wert wird 16-mal nach links geschoben, Resultat ist wieder 
ein int.  Vorsicht bei 16-Bit-Int-Systemen!

> - hier tritt der mögliche Datenverlust auf und der GCC warnt mich.

Nein, die Warnung kommt bei der Zuweisung eines (signed) int an ein 
uint32_t.

> Mit der Änderung
1
    GPIOx->BSRR = (uint32_t) bit<<16U;
> wird "bit" direkt passend kovertiert und der Zwischenschritt über einen
> signed integer bleibt aus. Habe ich das richtig verstanden?

Genau.  Und nur so auf Systemen mit 16-Bit-Ints korrekt.

Btw, der cast bezieht sich auf bit, nicht auf das Ergebnis des Shifts. 
Ich würde die Leerstellen deshalb anders setzen:
1
    GPIOx->BSRR = (uint32_t)bit << 16;

von (prx) A. K. (prx)


Lesenswert?

Während bei Operatoren wie + und * das Vorzeichen der rechten Seite 
genau wie der linken Seite den Typ des Ergebnisses bestimmt, ist das bei 
den Shift-Operatoren nicht der Fall. Weshalb das U in 16U hier also 
nichts am Vorzeichentyp des Ergebnisses ändert. Folglich ist "bit << 
16U" bei 32-Bit ein "int", "bit + 16U" aber ein "unsigned".

von (prx) A. K. (prx)


Lesenswert?

NB: Auf 32-Bit Maschinen wie diesem ARM ergibt es generell wenig Sinn, 
in Parametern und lokalen Variablen einen kleineren Typ als 32 Bits zu 
verwenden. Ausser es geht darum, den Wertebereich vorsätzlich darauf 
einzuschränken um keine anderen Werte zuzulassen. Dagegen kann die 
Verwendung kleinerer Typen bei ARMs zu umständlicherem Code führen, da 
es in Registern dafür keine Befehle gibt.

von Martin (Gast)


Lesenswert?

Du musst 16UL schreiben, dann ist die Warning weg

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.