Forum: Compiler & IDEs Promotion sein lassen?


von Walter T. (nicolas)


Lesenswert?

Hallo zusammen,

Alle Jahre wieder: Man meint, so langsam C verstanden zu haben, und dann 
bringt der Compiler eine Warnung, die ich nicht nachvollziehen kann:
1
#define GLCD_KS0108_DISPWIDTH 64U
2
3
// [....]
4
5
void foo(void)
6
{
7
    uint_fast16_t idx = 0U;
8
    idx += GLCD_KS0108_DISPWIDTH;
9
}

und bekomme vom Compiler (MinGW 64) die Warnung:
1
blblabla.c:18:31: warning: conversion to 'uint_fast16_t {a
2
ka short unsigned int}' from 'unsigned int' may alter its value [-Wconversion]
3
 #define GLCD_KS0108_DISPWIDTH 64U

OK - der Compiler jammert herum, daß "64U" ein längerer Datentyp als 
"unsigned short" ist. Da es keinen Modifier für "short" gibt, ändere ich 
also:
1
#define GLCD_KS0108_DISPWIDTH 64U
2
3
// [....]
4
5
void foo(void)
6
{
7
    uint_fast16_t idx = 0U;
8
    idx += (uint_fast16_t) GLCD_KS0108_DISPWIDTH;
9
}
Dann jammert der Compiler:
1
blablabla.c:322:20: warning: conversion to 'uint_fast16_t {
2
aka short unsigned int}' from 'int' may alter its value [-Wconversion]
3
             idx += (uint_fast16_t) GLCD_KS0108_DISPWIDTH;

Die "Integral Promotion"-Regel wandelt wohl meine "64U" in der Addition 
in einen "int", damit der Compiler direkt nach der Summenbildung kurz 
darauf jammern kann. Undgefähr wie das Kleinkind, das seine Rassel auf 
den Boden wirft, um danach schreien zu können.

Wie bringe ich jetzt meinem Compiler bei, daß er ohne Angst zu einer 
Zahl vom Datentyp "uint_fast16_t" einen Wert 64 addieren darf?

Viele Grüße
Nicolas

von Jens W. (jensw)


Lesenswert?

Dann lass doch bei der 64 einfach das U weg. Was ist denn dann?
Mault der dann immer noch? Sollte nicht sein.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Naja, die ausführliche Variante sollte gehen:
1
  idx = (uint_fast16_t) (idx + GLCD_KS0108_DISPWIDTH);

von Walter T. (nicolas)


Lesenswert?

Jens W. schrieb:
> Dann lass doch bei der 64 einfach das U weg. Was ist denn dann?

Dann passiert natürlich das Gleiche: Er erinnert mich höflich daran, daß 
ich einen Int in Unsigned Int konvertiere.

Jörg W. schrieb:
> Naja, die ausführliche Variante sollte gehen:

Ist das wirklich die Antwort? Ich muß für einen Datentyp mit 
plattformabhängiger Breite andere Operatoren verwenden? Ich bin gerade 
bass erstaunt.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Naja, a += b ist ja nur die Kurzschreibweise für a = a + b.  Wenn nun
bei letzterem aber eine Typumwandlung impliziert wird, über die der
Compiler dich warnt, und du diese Warnung loswerden möchtest, dann
musst du ihm das per Typecast sagen.  Dafür musst du aber die gesamte
rechte Seite casten, und das geht in der Kurzschreibweise nun einmal
nicht.

Alternative wäre es, ebendiese Warnung (ggf. nur für die Funktion)
abzuschalten.

von Walter T. (nicolas)


Lesenswert?

Danke für die Antworten!

An dieser lapidaren, schulterzuckenden Antwort auf die implizite Frage: 
"Warum macht ein C-Compiler aus der einfachen Addition zweier 
vorzeichenloser Zahlen zwei Typumwandlungen, nur weil die Variablen in 
einen vorzeichenbehafteten Datentyp hineinpassen ???" lese ich:
"Für Leute, die mit Computerzeuchs klarkommen, ist soetwas völlig 
normal." Dieses Computerzeuchs ist nichts für mich. Aber danke, daß ihr 
mir trotzdem dabei helft!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Walter T. schrieb:
> Für Leute, die mit Computerzeuchs klarkommen, ist soetwas völlig normal.

Naja, die integer promotion rules sind schon ein ziemlich spezielles
Ding.  Vermutlich würde man das aus heutiger Sicht anders lösen und
die integer promotion nur dann anwenden, wenn tatsächlich verschiedene
Datentypen vorliegen.  C ist halt keine moderne Programmiersprache,
sondern schon über 40 Jahre alt.

Was ein gängiges Missverständnis dabei ist ist, dass die linke Seite
einer Zuweisung irgendeinen Einfluss auf die Berechnung des Ausdrucks
auf der rechten Seite hat: dieser steht syntaktisch erstmal komplett
für sich, und das kann auch nicht anders sein: idx +
GLCD_KS0108_DISPWIDTH muss sich in der Zuweisung halt genauso verhalten,
wie wenn du es an eine Funktion übergibst oder als Index in ein Array
benutzt.

von Sebastian V. (sebi_s)


Lesenswert?

Vielleicht solltest du das -Wconversion Flag rausnehmen. Ich hab das 
gerade aus Spaß mal in einem kleinen Projekt von mir aktiviert und 
direkt 250 Warnungen gekriegt. Und da überall Casts einzubauen hätte ich 
keine Lust und es Stört auch die Lesbarkeit des Quelltextes wie ich 
finde. Die Warnung mag ja gut gemeint sein aber leider ziemlich 
unbrauchbar für echte Projekte. Die implizieren Konvertierungen gehören 
nunmal (leider) zu C/C++ dazu.

von Hannes J. (Firma: _⌨_) (pnuebergang)


Lesenswert?

Walter T. schrieb:
> Ist das wirklich die Antwort? Ich muß für einen Datentyp mit
> plattformabhängiger Breite andere Operatoren verwenden? Ich bin gerade
> bass erstaunt.

Ja, der Standard ist da etwas ... In einem alten Technical Corrigendum 
wurde zwischen Standards nochmal dran rumgebastelt, was es auch nicht 
besser machte.

Arithmetische Operationen wie '+' werden mit mindestens 'unsigned int' 
oder 'signed int' ausgeführt. Beides lässt sich nicht ohne Verlust an 
dein 'uint_fast16_t idx' zuweisen.

GCC hat eine Erweiterung, dass man Lvalues casten kann, die ist 
allerdings meines Wissens seit einiger Zeit deprecated. Du kannst mal
1
(unsigned)idx += GLCD_KS0108_DISPWIDTH;

versuchen.

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.