Suffix bei konstanten Werten

OP #2675602
Hallo zusammen,

ich habe schon öfter im Code das Suffix U (unsigned) hinter konstanten 
Werten gesehen, also z.B.:

int tmp;
tmp = 15U;

Was hat die Kennzeichnung als unsigned für einen Sinn? Macht der GCC 
dann spezielle Operationen? Wie sieht das mit L (Long) aus?

Viele Grüße
Gast
In deinem Beispiel macht es keinen Sinn.

Der Suffix ist optional und nicht GCC spezifisch, sondern z.B. im C99 
Standard enthalten. Er spezifiziert den Typ einer Ganzzahlkonstanten und 
hat Auswirkungen darauf, wie ein Ausdruck mit dieser Konstanten 
ausgewertet wird. Im einfachsten Fall ersetzt es einen Cast.
Beispiel, wo es einen Unterschied macht:
Auf einem Rechner mit 4 Byte für int könnte man folgendes schreiben:
1
#include <stdlib.h>
2
#include <stdio.h>
3

4

5
int main( int nargs, char **args )
6
{
7
    unsigned long long   ul = 4000*1000000;
8

9
    printf( "%llu\n", ul );
10

11
    return 0;
12
}
Das ergibt fälschlicherweise (Ubuntu, gcc):
18446744073414584320

Grund: sowohl 4000 als auch 1000000 sind (signed) int, also wird die 
Berechnung in int ausgeführt. Das Produkt daraus überschreitet den 
Wertebereich aber, und zwar gerade so, daß das höchste Bit gesetzt ist 
(hexadezimal: 0xee6b2800).
Das Ergebnis wird zur Zuweisung auf 8 Byte aufgeblasen, und weil es eine 
int mit gesetztem Bit ist, wird dieses vermeintliche Vorzeichenbit auf 
die neuen 4 Byte aufgezogen (0xffffffffee6b2800).
Mit printf als unsigned long long ausgegeben wird dann eine viel zu 
große positive Zahl daraus.


Andere Variante:
1
#include <stdlib.h>
2
#include <stdio.h>
3

4

5
int main( int nargs, char **args )
6
{
7
    unsigned long long   ul = 4000u*1000000u;
8

9
    printf( "%llu\n", ul );
10

11
    return 0;
12
}
Das ergibt jetzt korrekt:
4000000000

Jetzt wird nämlich ein Produkt aus zwei unsigned berechnet, ebenfalls 
wieder als Bitmuster 0xee6b2800. Weil dem Compiler aber klar ist, daß es 
unsigned ist, wird beim Erweitern auf 8 Byte das oberste Bit ignoriert 
und nur 0x00... vorne ergänzt. Das resultierende 0x00000000ee6b2800 ist 
in dezimal die erwartete 4000000000.
OP
Super Antwort, danke schön!
Hatte mir so etwas in die Richtung schon gedacht. Aber bei Werten die 
als Zustandsbeschreibung genutzt werden, hat es dann keinen tieferen 
Sinn. Also zeugt das nur von einem gutem Programmierstil, wenn man es 
einfach immer benutzt.
Gast
Peter Dannegger schrieb:
> Bei einer Zuweisung ist der Suffix unnötig.

Wenn man darauf Wert legt, daß der Compiler z.B. nur die Routinen
für float-Berechnungen und nicht für double-Arithmetik benutzt,
ist es sinnvoll auch bei Zuweisungen einen Suffix zu verwenden.
Das trifft im weiteren auch auf Konstanten in Berechnungen zu.


float pi;

pi=3.1415926F;

grad=3.1415926F*rad/4.0F;
Gast
./. schrieb:
> float pi;
>
> pi=3.1415926F;

Welchen Unterschied erwartest du bei dieser Anweisung ohne das F?

> grad=3.1415926F*rad/4.0F;

Hier wird es ja wieder als Teil einer Berechnung verwendet und nicht 
einfach nur zugewiesen.
Gast
>> float pi;
>>
>> pi=3.1415926F;

Das ist mir mal bei Renesas-Compilern aufgefallen.

Ohne das F an den Konstanten landeten immer Teie der recht umfänglichen
double-Library im viel zu kleinen Flash.
Und ich brauchte nur float.

Ob das jetzt standardkonform ist, will ich gar nicht beurteilen.
./. schrieb:
>>> float pi;
>>>
>>> pi=3.1415926F;
>
> Das ist mir mal bei Renesas-Compilern aufgefallen.
>
> Ohne das F an den Konstanten landeten immer Teie der recht umfänglichen
> double-Library im viel zu kleinen Flash.
> Und ich brauchte nur float.
>
> Ob das jetzt standardkonform ist, will ich gar nicht beurteilen.

Dazu hat der Standard nichts zu sagen.
Der Standard kümmert sich nicht um Implementierungen sondern beschreibt 
das geforderte Verhalten eines Programms.
Nach Ausführung der Zeilen muss der Wert in der Variablen stehen. Wie er 
dorthin gelangt ist Sache des Compilers.
./. schrieb:

> Ohne das F an den Konstanten landeten immer Teie der recht umfänglichen
> double-Library im viel zu kleinen Flash.
> Und ich brauchte nur float.

Das kann passieren, muss aber nicht. Abgesehen von Berechnung von 
konstanten Ausdrücken in einem Kontext, der eine Konstante erwartet, 
sind Optimierungen im Standard nicht vorgeschrieben.

Allerdings hätte man schon erwarten können, dass die konstante 
Umrechnung einer double Konstanten in eine float Konstante vom Compiler 
übernommen und nicht erst zu Laufzeit durchgeführt wird.
Persönliche Seite
Die Suffix spielt auch bei folgendem Code eine Rolle, Seispiel avr-gcc:
1
void a ();
2

3
void f (void)
4
{
5
    asm volatile ("" :: "r" (0l));
6
    a (-1l);
7
}

Ohne die Suffix werden 16-Bit Werte bereitgestellt, Mit dem L werden es 
32-Bit Werte.

A. K. schrieb:

> Allerdings hätte man schon erwarten können, dass die konstante
> Umrechnung einer double Konstanten in eine float Konstante vom
> Compiler übernommen und nicht erst zu Laufzeit durchgeführt wird.

Das setzt u.U eine komplette float- und double Emulation im Compiler 
voraus, da er sicherstellen muss, daß sich zB das Rundungsverhalten 
nicht durch die Optimierung ändert.

Selbst wenn auf dem Host-Rechner, auf dem der Compiler läuft, eine FPU 
vorhanden ist, kann diese nur dann verwendet werden, wenn die Ergebnisse 
genauso sind wie auf dem Target. Das genaue Verhalten kann etwa vom 
jeweiligen float-Layout abhängen.

Dies ist auch der Grund dafür, daß GCC Bibliotheken wie GMP und MPFR 
verwendet und voraussetzt: GCC verwendet nicht die Host-FPU für solche 
Compilezeit-Optimierungen, sondern macht alle Berechnungen per Emulation 
und mit dem Layout wie auf dem Target.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 14 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.