mikrocontroller.net

Forum: Compiler & IDEs Woher Infos zum kleinsten impliziten Datentyp?


Autor: Verunsichert (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mein Problem:

Ich habe einen Tag nach einem Fehler gesucht, der beim Compilieren mit 
einer älteren Compilerversion nicht aufgetreten ist. Und zwar ging es um 
eine Leftshiftoperation die das 19. Bit als Maske zum Vergleich mit 
einem 32Bit Wert setzen sollte. Plattform war ein Controller von 
Renesas. Mir geht es aber jetzt darum, wo ich NACHLESEN kann, wie der 
Compiler das handhabt um in Zukunft Bescheid zu wissen und nicht raten 
zu müssen. Insbesondere auch beim AVR-GCC für 8bitter. Oder ist das 
keine Sache des Compilers?

Mein code sah so aus:
#define WARNUNG 19
u32 32BitWert = 0;
...
if (32BitWert & (1<<WARNUNG) {
  //Merker
}

Mit dem alten Compiler funktionierte das. Mit dem neuen gab es aber 
keine Fehlermeldung, sondern die If-Abfrage war einfach nie erfüllt und 
"Merker" wurde nie erreicht (vermutlich sogar wegoptimiert).

Abhilfe schafft natürlich ein expliziter cast:
#define WARNUNG 19
u32 32BitWert = 0;
...
if (32BitWert & ((u32)1<<WARNUNG) {
  //Merker
}

Aber ab wann ist dieser explizite cast nötig?
Dazu muss ich wissen, was ohne den expliziten cast implizit gemacht 
wird!
Wenn WARNUNG als 0 bis 7 definiert wird gibt es vermutlich nie Probleme, 
da alles in ein Byte passt. Bei einem Shift um 8 muss schon ein 16 Bit 
Wert implizit vorausgesetzt werden.

Meine Frage: Wo finde ich die Information, die mir hier Gewissheit 
verschafft? Ist das eine Sache des Compilers, der Standardlib, oder wer 
legt das fest?
Vielen Dank für Hinweise.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Abschnitt 6.3.1.8: Usual arithmetic conversions, 2005 ISO/IEC 9899:TC2 
(Committee Draft -- May 6).

http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Verunsichert schrieb:

> Meine Frage: Wo finde ich die Information, die mir hier Gewissheit
> verschafft? Ist das eine Sache des Compilers, der Standardlib, oder wer
> legt das fest?

Das ist eine Sache des C-Standards.

Grob gesagt:
Alles was kleiner als ein int ist, wird implizit zu einem int 
umgecastet.
Ganzzahl-Zahlenkonstante sind ohne Datentypangabe immer int, es sei denn 
die Zahl passt nicht in einen int, dann ist es implizit ein long.

In
  1<<WARNUNG

ist also sowohl 1, als auch WARNUNG (da ja als Zahl zwischen 0 und 7 
definiert) ein int.

Jetzt hängt es natürlich davon ab, wie gross ein int auf deinem Compiler 
ist. Und das kann sich (im Prinzip) der Compiler aussuchen. Bei einem 
generischen int handelt es sich um 'die auf dieser Maschine natürliche 
Breite einer Zahl zum rechnen, aber nicht kleiner als 16 Bit'. D.h. ein 
int ist mindestens 16 Bit, kann aber auch größer sein (zb auf einer 32 
Bit Maschine wird int meistens 32 Bit sein)

Wenn dein Code darauf angewiesen ist, dass bestimmte Datentypen minimale 
Längen haben (weil Konstante benutzt werden), die über den 
Minimalanforderungen der definierten Datentypen liegen (die findet man 
im C-Standard), dann ist man gut beraten, entweder
* die neuen Datentyp-typedefs zu benutzen
  int32_t
  uint32_t
  etc.
* Zahlenkonstante zu casten
  das geht zb besonders gut, wenn man mit define arbeitet

#define WARNUNG 19
#define WARNUNG_MASK    ((uint32_t)1 << WARNUNG)


if (32BitWert & WARNUNG_MASK ) {

* Wenn man eine Ausgabemöglichkeit hat, evtuell am Programmanfang zu 
testen oder ein assert einzubauen

assert( sizeof(int) > 2 )

letzteres geht nur dann vernünftig, wenn sizeof(char) tatsächlich 
Bytegröße hat. sizeof(char) ist per Def immer 1. Aber das muss nicht 
bedeuten, dass es sich dabei um 1 Byte handelt. Ist zwar meistens so, 
aber das ist nicht garantiert.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dafür gibts dann CHAR_BIT aus <limits.h>.

Autor: Verunsichert (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank für die Tipps!

Würde bei
#define WARNUNG_MASK    ((uint32_t)1 << WARNUNG)
auf einem 32Bit System der Cast wegoptimiert? So dass man ihn 
sicherheitshalber besser macht?

Wenn es im C-Standard definiert ist, aber der Compiler es anders 
handhaben kann, müsste dann nicht beim Compiler dazu auch etwas zu lesen 
sein?
Würde auf einem Atmega8 also implizit bei
if (32BitWert & (1<<WARNUNG) {
ein 16Bit Wert für die 1 angenommen werden?

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Würde bei
> #define WARNUNG_MASK    ((uint32_t)1 << WARNUNG)
> auf einem 32Bit System der Cast wegoptimiert?

Was meinst du mit "wegoptimiert?" Wenn der Wert schon 32 Bit breit ist, 
macht der Cast doch sowieso nichts.

> Wenn es im C-Standard definiert ist, aber der Compiler es anders
> handhaben kann, müsste dann nicht beim Compiler dazu auch etwas zu lesen
> sein?

Ja. Die ISO-Norm schreibt auch vor, daß es in der Dokumentation des 
Compilers stehen muß.

> Würde auf einem Atmega8 also implizit bei
> if (32BitWert & (1<<WARNUNG) {
> ein 16Bit Wert für die 1 angenommen werden?

"angenommen" würde ich nicht sagen. Er definiert einfach, daß der Wert 
16 Bit breit ist.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Verunsichert schrieb:
> Vielen Dank für die Tipps!
>
> Würde bei
> #define WARNUNG_MASK    ((uint32_t)1 << WARNUNG)
> auf einem 32Bit System der Cast wegoptimiert? So dass man ihn
> sicherheitshalber besser macht?

:-)
Du kannst davon ausgehen, dass KEINE Erweiterung auf 32 Bit stattfindet, 
wenn der Zahlenwert schon als 32 Bit Wert vorliegt. Und etwas anderes 
macht ja dieser Cast nicht.

> Wenn es im C-Standard definiert ist, aber der Compiler es anders
> handhaben kann,

langsam.
Der Standard verlangt gewisse Minima. Der Compiler kann diese Minima 
übertreffen. Daher ist es gut 2 Dinge zu kennen
* was sind die Minima
* inwieweit übertrifft der Compiler diese Minima
Dazu kommt, dass COmpiler auch oft über Commandline Switches verfügen, 
mit denen die 'Minima' abgesenkt werden können. So kann man den avr-gcc 
per Commandline Switch dazu zwingen, einen int als 8-Bit int 
aufzufassen. Das kann man benutzen, man muss allerdings dann sehr genau 
wissen was man tut. Stichwort: Libraries wurden zb ohne diesen Switch 
erstellt. Ein malloc erwartet trotzdem 16 Bit.

> müsste dann nicht beim Compiler dazu auch etwas zu lesen
> sein?

In den Header Files stehen die Werte drinnen.

> Würde auf einem Atmega8 also implizit bei
> if (32BitWert & (1<<WARNUNG) {
> ein 16Bit Wert für die 1 angenommen werden?

Mit dem avr-gcc: ja

Autor: Verunsichert (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen vielen Dank!

Auch wenn es sicherlich Basics sind und viele müde darüber lächeln 
mögen, mir hat die Erklärung wirklich sehr geholfen.
Das war eine wichtige Lektion, die ich mir merken werde.

Autor: Verunsichert (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nachtrag:
Insbesondere weil einen das in vielen Fällen gar nicht kümmert oder 
kümmern muss. Ich bin bisher immer so hingekommen, ohne mich damit 
auseinander zu setzen.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Verunsichert schrieb:
> Nachtrag:
> Insbesondere weil einen das in vielen Fällen gar nicht kümmert oder
> kümmern muss. Ich bin bisher immer so hingekommen, ohne mich damit
> auseinander zu setzen.

Die von dir geschliderte Problematik tritt auf Desktopsystemen eher 
selten auf.

Die von dir beobachtete Problematik tritt meistens auf, wenn man den 
Compilerhersteller insgesamt wechselt. Seltener kommt es zu solchen 
Problemen, wenn man auf eine neuere Version des COmpilers wechselt. Ich 
kenne keinen Compiler, bei dem bei einem Versionssprung die Datentypen 
kürzer wurden. Wenn, dann wurden sie länger.

Was natürlich aber sein kann:
Optimizer werden ständig verbessert. Programmiert man daher am 
C-Standard vorbei und hat Glück dass der Optimizer in der alten Version 
genau das erzeugt hat, was man ungerechtfertigterweise erwartet hat, 
dann landet man bei einem neueren Optimizer irgendwann in der Breduille.

Und dann gibt es natürlich auch noch den Fall, dass der Compiler 
fehlerhaft war und das in einer neuen Version korrigiert wurde.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich sags ja immer, uns fehlt ein Compiler, bei dem:
* ein char 13 Bit hat
* short, int und long alle 5 Bytes breit sind
* die Integer-Darstellung eines Zeigers einer zufälligen Zahl entspricht 
(insbesondere (char *)((int)zeiger + 1) nicht aufs nächste Zeichen 
zeigt)
* ...

:-}

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.