Forum: Compiler & IDEs 32-Bit Wert in 8-Bit Variable schreiben


von Wunderer (Gast)


Lesenswert?

Wie kommt es eigentlich, dass das hier:
1
unsigned char a;
2
unsigned int b = 0x12345678;
3
a = b;

keine Warnung ergibt, aber das hier:
1
unsigned char a;
2
a = 0x12345678;

schon? (warning: large integer implicitly truncated to unsigned type)

Mathematisch gesehen läuft es doch wohl aufs gleiche raus... ich meine 
die Variable a hat danach so oder so den gleichen Wert, und in beiden 
Fällen wollte man mehr in sie reinstecken als reinpasst ;-)
Ist das nur beim gcc so oder ist das generell ANSI-C Standard?

von Karl H. (kbuchegg)


Lesenswert?

Wunderer schrieb:
> Wie kommt es eigentlich, dass das hier:
>
>
1
> unsigned char a;
2
> unsigned int b = 0x12345678;
3
> a = b;
4
>
>
> keine Warnung ergibt, aber das hier:
>
>
1
> unsigned char a;
2
> a = 0x12345678;
3
>
>
> schon? (warning: large integer implicitly truncated to unsigned type)
>
> Mathematisch gesehen läuft es doch wohl aufs gleiche raus...

Ja. Für dich schon.
Im Prinzip könnte der Compiler im ersten Beispiel das genauso 
detektieren, wenn er sich den Datenfluss ansieht und verfolgt, welche 
Variable wann welchen Wert hat. Nur wind wohl die Compilerbauer davon 
ausgegangen, das das so keiner machen wird. Für den Compiler steht da 
erst mal einfach nur

    a = b;

b ist eine Variable und damit wird erst mal nichts über den Inhalt der 
Variablen angenommen. b könnte ja durchaus einen Inhalt haben, der 
problemlos in a hineinpasst und dann wäre diese Warnung unangebracht. 
Ganz im Gegenteil: In dein meisten Programmen würde es dann vor solchen 
Warnungen nur noch so wimmeln. C legt (anders als andere Sprachen) da 
einfach mehr Verantwortung auf den Programmierer. Oder anders gesagt: 
Wenn du eine Tante brauchst, die mit dir Lulu geht, dann bist du bei C 
an der falschen Sprache.

> Ist das nur beim gcc so oder ist das generell ANSI-C Standard?

Der Sprachstandard verlangt von einem Compiler überhaupt keine 
Warnungen. Warnungen sind Good-will Dinge, die ein Compilerbauer von 
sich aus einbaut.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Wunderer schrieb:

> Wie kommt es eigentlich, dass das hier:
> ...
> keine Warnung ergibt, aber das hier:
> ...
> schon? (warning: large integer implicitly truncated to unsigned type)

Wie sieht deine Kommandozeile beim Kompilieren aus? Hast du alle 
Warnungen eingeschaltet (-Wall oder -Wextra) oder nicht?

Interessant ist für dich auch -Wconversion und -Wno-sign-conversion
http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html

Bei

unsigned char a;
unsigned int b = 0x12345678;
a = b;

sollte es im Idealfall letztendlich zwei Warnungen geben, wenn int 
16-Bit groß ist.

Dafür: unsigned int b = 0x12345678;
und dafür: a = b;

von Rolf Magnus (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
>> Ist das nur beim gcc so oder ist das generell ANSI-C Standard?
>
> Der Sprachstandard verlangt von einem Compiler überhaupt keine
> Warnungen. Warnungen sind Good-will Dinge, die ein Compilerbauer von
> sich aus einbaut.

Naja, es gibt durchaus Stellen, an denen der Compiler verpflichtet ist, 
eine "diagnostic message" auszugeben.

von Wunderer (Gast)


Lesenswert?

Stefan B. schrieb:
> Wie sieht deine Kommandozeile beim Kompilieren aus? Hast du alle
> Warnungen eingeschaltet (-Wall oder -Wextra) oder nicht?

-Wall ist aktiviert, damit gibt es genau die eine Warnung die ich oben 
"copy and pasted" habe. Die gcc Version hierbei ist:
gcc (GCC) 3.4.5 (mingw-vista special r3)

"int" ist bei mir übrigens 32 Bit groß.

Ach ja und die Erklärung von Karl heinz Buchegger finde ich nicht 
wirklich überzeugend. Gerade wenn man sowas hier macht:

1
int Sendedatum = 0x12345678;
2
unsigned char Sendepuffer[sizeof(int)];
3
  
4
Sendepuffer[0] = Sendedatum >>  0;
5
Sendepuffer[1] = Sendedatum >>  8;
6
Sendepuffer[2] = Sendedatum >> 16;
7
Sendepuffer[3] = Sendedatum >> 24;

finde ich es befremdlich dass es hierbei keinerlei Warnungen gibt. Das 
ist so wie wenn ich zu viel Wasser in einen Eimer einfülle und die 
Laufzeitumgebung mich nicht warnt, dass es dann einen Verlust an Wasser 
gibt. (ups :)

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Wunderer schrieb:

> gcc (GCC) 3.4.5 (mingw-vista special r3)
> "int" ist bei mir übrigens 32 Bit groß.

Ah, klar dann.

> finde ich es befremdlich dass es hierbei keinerlei Warnungen gibt.

http://www.umfi.de/prospr.htm

von Rolf Magnus (Gast)


Lesenswert?

Wunderer schrieb:

> Das ist so wie wenn ich zu viel Wasser in einen Eimer einfülle und die
> Laufzeitumgebung mich nicht warnt, dass es dann einen Verlust an Wasser
> gibt. (ups :)

Dir geht es aber nicht um die Laufzeitumgebung, sondern um den Compiler. 
Du erwartest also vom Hersteller des Wasserhahns, daß er dich vor dem 
Befüllen des Eimers darüber informiert, daß er möglicherweise überlaufen 
könnte, wenn du den Wasserhahn nicht rechtzeitig zudrehst.

von Wunderer (Gast)


Lesenswert?

Die Mechanismen im Compiler sind aber meines Erachtens schon da, wie 
meine im ersten Post gezeigte Warnung zu beweisen scheint. Warum man 
diese Möglichkeit dann nicht konsequent nutzt: Das ist es, was ich nicht 
verstehe.

von Rolf Magnus (Gast)


Lesenswert?

Wunderer schrieb:
> Die Mechanismen im Compiler sind aber meines Erachtens schon da, wie
> meine im ersten Post gezeigte Warnung zu beweisen scheint.

Dort wird direkt eine Konstante einer Variablen zugewiesen, die für den 
Wert zu klein ist. Das kann eigentlich nur ein Fehler sein, denn warum 
sollte jemand da einen fixen Wert hinschreiben, der gar nicht in die 
Zielvariable paßt?
Anders ist das, wenn man eine Variable einer anderen zuweist. Da kann 
das Abschneiden gewollt sein oder es kann schon vorher sichergestellt 
worden sein, daß der Wert paßt.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Visual C++ sagt dazu:
Fall 1 (a=b):
1
warning C4244: '=' : conversion from 'unsigned long' to 'unsigned char', possible loss of data

Der zweite Fall ist gleich 2 Warnungen wert:
1
warning C4305: '=' : truncation from 'const int' to 'unsigned char'
2
warning C4309: '=' : truncation of constant value

> Beitrag #1877308 wurde gelöscht.
> Ausser den trivalsten Programmen, wird es dann nur
> so von Warnungen wimmeln.
Ich nehme Visual C++ als Entwicklungsplattform und Editor. Dann drücke 
ich zwischendurch schon mal auf den Compilieren-Button. Und dann hat da 
nichts zu wimmeln... :-o

von Daniel (Gast)


Lesenswert?

Wunderer schrieb:
> Warum man
> diese Möglichkeit dann nicht konsequent nutzt: Das ist es, was ich nicht
> verstehe.

Weil die Fehlermeldung extrem nervig wäre! Beispiele:
1
int32_t a;
2
int32_t b;
3
int8_t  diff;
4
5
/* Sinnvoll, wenn der Programmierer weiß, dass die Differenz nie
6
   größer als der Wertebereich von int8_t ist.  */
7
diff = a - b;

oder:
1
uint16_t word;
2
uint8_t  LB;
3
uint8_t  HB;
4
5
LB = word;
6
HB = word>>8;

Gruß

von Wunderer (Gast)


Lesenswert?

Rolf Magnus schrieb:
> Anders ist das, wenn man eine Variable einer anderen zuweist. Da kann
> das Abschneiden gewollt sein

Ich dachte für sowas (unter anderem) gibt es casts :-O

von Karl H. (kbuchegg)


Lesenswert?

Wunderer schrieb:
> Rolf Magnus schrieb:
>> Anders ist das, wenn man eine Variable einer anderen zuweist. Da kann
>> das Abschneiden gewollt sein
>
> Ich dachte für sowas (unter anderem) gibt es casts :-O

Ja.
Aber gerade in der µC Programmierung wimmelt es dann nur so von Casts.
Casts sind aber Waffen! Wenn es nicht sein muss, dann castet man nicht 
freiwillig.
Ausserdem: Was bringts dir, wenn du dann ganz einfach überall einen Cast 
hinmachst? Dadurch ist nichts gewonnen, die Dinge können aber (bei 
Änderungen) noch viel schlimmer werden - durch den Cast!

Und wer in seinem Programm nicht soweit Ordnung halten kann, dass er 
beim automatischen Runtercasten auf einen kleineren Datentyp nicht auf 
die Nase fällt, ...... der hat dann ganz schnell noch ganz andere, viel 
schwerwiegendere Probleme.

von Wunderer (Gast)


Lesenswert?

Na gut, dann kann ich ja das hier vom Kollegen:
1
Sende_Puffer [0] =  (UINT8)  (Variable_32Bit & 0x000000FF);
2
Sende_Puffer [1] =  (UINT8) ((Variable_32Bit & 0x0000FF00) >>  8);
3
Sende_Puffer [2] =  (UINT8) ((Variable_32Bit & 0x00FF0000) >> 16);
4
Sende_Puffer [3] =  (UINT8) ((Variable_32Bit & 0xFF000000) >> 24);

beruhigt verkürzen in:
1
Sendepuffer[0] = Variable_32Bit;
2
Sendepuffer[1] = Variable_32Bit >>  8;
3
Sendepuffer[2] = Variable_32Bit >> 16;
4
Sendepuffer[3] = Variable_32Bit >> 24;

Ich hatte zuerst gedacht, das Gecaste und Ver-UND-ere hätte einen Sinn 
;-)

von Karl H. (kbuchegg)


Lesenswert?

Wunderer schrieb:

> Ich hatte zuerst gedacht, das Gecaste und Ver-UND-ere hätte einen Sinn
> ;-)

Solange sicher gestellt ist, dass der Datentyp von Sendepuffer immer 
unsigned char (bzw UINT8) ist, kannst du dir das sparen.

von Wunderer (Gast)


Lesenswert?

*spart sich was.*

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Wunderer schrieb:
> Wie kommt es eigentlich, dass das hier:
>
> unsigned char a;
> unsigned int b = 0x12345678;
> a = b;
>
> keine Warnung ergibt, aber das hier:
>
> unsigned char a;
> a = 0x12345678;
>
> schon?

Weil das eine Äpfel sind und das andere Birnen. Um für Birnen zu warnen 
fehlt das -Wconversion.

von Wunderer (Gast)


Lesenswert?

Johann L. schrieb:
> Weil das eine Äpfel sind und das andere Birnen. Um für Birnen zu warnen
> fehlt das -Wconversion.

Macht bei mir genau gar keinen Unterschied:

D:\Dateien\C\32in8warning>gcc -Wconversion main.c -o 32in8bit.exe
main.c: In function `test2':
main.c:14: warning: large integer implicitly truncated to unsigned type

D:\Dateien\C\32in8warning>gcc -Wall main.c -o 32in8bit.exe
main.c: In function `test2':
main.c:14: warning: large integer implicitly truncated to unsigned type

von Rolf Magnus (Gast)


Lesenswert?

Wunderer schrieb:
> Rolf Magnus schrieb:
>> Anders ist das, wenn man eine Variable einer anderen zuweist. Da kann
>> das Abschneiden gewollt sein
>
> Ich dachte für sowas (unter anderem) gibt es casts :-O

Laut ISO-C ist kein Cast nötig, wenn man von einem größeren Typ in einen 
kleineren kopiert. Das gilt im Übrigen sowohl für Variablen, als auch 
für Konstanten, denn sonst müßte das da auch schon eine Warnung geben:
1
char c = 1;

Schließlich ist 1 vom Typ int, der (auf den meisten Plattformen) größer 
ist als char, und damit wäre es wie in diesem Fall, wo er deiner Meinung 
nach eine Warnung bringen sollte:
1
int i = 1;
2
char c = i;

In solchen Fällen warnt gcc deshalb nicht. Erst wenn man eine Konstante 
zuweist, die tatsächlich einen Wert hat, der außerhalb dessen liegt, was 
der Zieldatentyp aufnehmen kann, gibt es eine Warnung.
Einerseits muß der Compiler ja den Wert kennen, was eine Konstante 
voraussetzt, zweitens kann er bei dieser davon ausgehen, daß es keine 
Absicht war.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Wunderer schrieb:
> Johann L. schrieb:
>> Weil das eine Äpfel sind und das andere Birnen. Um für Birnen zu warnen
>> fehlt das -Wconversion.
>
> Macht bei mir genau gar keinen Unterschied:

Liegt vielleicht an der GCC-Version. Meine horcht auf 4.5.1

von Wunderer (Gast)


Lesenswert?

Und -Wconversion ist nicht in -Wall enthalten? Von wegen "all" = alle...

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.